Thursday, March 5, 2009

O scurtă introducere în UTF8

1. Introducere
Acest articol este o scurtă introducere în UTF8 din perspectiva sistemului de operare Linux. Articolul este dedicat tuturor celor ce întâmpină în mod regulat dificultăţi în setarea caracterelor diacritice româneşti în diferite programe sub Linux. Toate exemplele de mai jos au fost încercate pe o distribuţie Gentoo, şi se presupune că pot fi replicate cu uşurinţă şi pe alte tipuri de distribuţii.

Scopul declarat al acestui articol este de a vă lăsa cu impresia că orice este posibil, inclusiv să folosiţi litere precum ş şi ţ pe un calculator pe care tocmai aţi cheltuit o sumă indecentă de bani, şi care "by default" nu ştie decât engleză.

2. Ce este UTF-8
Standardul ASCII (American Standard Code for Information Interchange) stă la baza seturilor de caractere folosite în toate sistemele de operare moderne. A fost adoptat în anul 1968 sub numele ANSIX3.4. Conform ASCII, caracterele limbii engleze sunt mapate în numere întregi pe 8 biţi. Această mapare acoperă 256 de caractere literare şi de control diferite. Bineînţeles, 256 de caractere nu acoperă toate limbile globului, aşadar în decursul timpului alte forme de mapare au fost definite. După o serie de iteraţii s-a ajuns la Unicode.

Originile standardului Unicode pot fi trasate către Bell Laboratories care ne-au adus în decursul timpului limbajul de programare C, sistemul de operare Unix iar mai târziu C++. Mecanismul a fost descris mai întâi de Ken Thompson şi Robert Pike în anul 1993, ca stând la baza sistemului de procesare de text în noul lor sistem de operare Plan9. A fost preluat apoi de X/Open Group şi inclus în ghidul de portabilitate intitulat XPG4 care stă la baza specificaţie Unix98.

Adoptat de către ISO în 1996 devine astfel standard internaţional sub numele de ISO-10646. Acest standard este suportat sub Linux, iar unele distribuţii (spre exemplu Fedora) sunt setate default pentru UTF8.

După cum se menţionează la http://www.unicode.org/, standardul Unicode prevede un cod numeric unic pentru fiecare caracter, pe orice platformă hardware, în orice program software, şi în orice limbă. Unicode este compatibil cu standardul ASCII astfel încât un document tipărit în ASCII poate fi interpretat corect în Unicode, dar nu şi invers.

Caracterele româneşti sunt reprezentate de următoarele coduri Unicode:

â - U00e2; Â - U00C2;

ă - U0103; Ă - U0102;

î - U00ee; Î - U00ce;

ş - U015f; Ş - U015e;

ţ - U0163; Ţ - U0162;





UTF8 este în esenţă o metodă de serializare a codurilor de caractere Unicode pe mai mulţi octeţi.
0x00000000 - 0x0000007F: 0xxxxxxx
0x00000080 - 0x000007FF: 110xxxxx 10xxxxxx
0x00000800 - 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 - 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0x00200000 - 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x04000000 - 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

Caracterele româneşti sunt serializate pe doi octeţi în UTF8 după cum urmează:

ă - 0xc3, 0xa2; Â - 0xc3, 0x82;

ă - 0xc4, 0x83; Ă - 0xc4, 0x82;

î - 0xc3, 0xae; Î - 0xc3, 0x8e;

ş - 0xc5, 0x9f; Ş - 0xc5, 0x9e;

ţ - 0xc5, 0xa3; Ţ - 0xc5, 0xa2;

Exista trei lucruri despre care trebuie să discutăm în ceea ce priveşte o setare de caractere diacritice româneşti sub Linux: setarea tastaturii, setarea fonturilor şi setarea variabilei "locale".

3. Setare tastatură
Majoritatea tastaturilor comercializate în România sunt tastaturi de tip US. Aceasta se datoreşte preţului dar şi modului în care ne-am obişnuit să avem literele aşezate. Pe o asemenea tastatură putem mapa caracterele diacritice după cum urmează: cu tasta Alt din partea dreaptă a barei de spaţiu apăsată, tastele a, s, t, i devin diacritice, iar tasta q devine â.

Pentru a obţine acest efect începem prin a copia fişierul .Xmodmap în directorul home/user curent:

#cp /usr/lib/X11/etc/xmodmap.std .Xmodmap



Apoi, într-un program de editare modificăm .Xmodmap (sau cut&paste de aici). Rezultatul este următorul:
!
! $XFree86: xc/programs/Xserver/hw/xfree86/etc/xmodmap.std,v 3.4 1996/02/04 09:09:12 dawes Exp $
!
! Standard key mapping for XFree86 (for US keyboards).
!
! This file can be fed to xmodmap to restore the default mapping.
!
! $XConsortium: xmodmap.std /main/7 1996/02/21 17:48:55 kaleb $
!
! First, clear the modifiers
!
clear shift
clear lock
clear control
clear mod1
clear mod2
clear mod3
clear mod4
clear mod5
!
! Set the mapping for each key
!
keycode 8 =
keycode 9 = Escape
keycode 10 = 1 exclam
keycode 11 = 2 at
keycode 12 = 3 numbersign
keycode 13 = 4 dollar
keycode 14 = 5 percent
keycode 15 = 6 asciicircum
keycode 16 = 7 ampersand
keycode 17 = 8 asterisk
keycode 18 = 9 parenleft
keycode 19 = 0 parenright
keycode 20 = minus underscore
keycode 21 = equal plus
keycode 22 = BackSpace
keycode 23 = Tab
keycode 24 = q Q 0x000e2 0x000c2
keycode 25 = w W
keycode 26 = e E
keycode 27 = r R
keycode 28 = t T U00163 U00162
keycode 29 = y Y
keycode 30 = u U
keycode 31 = i I 0x000ee 0x000ce
keycode 32 = o O
keycode 33 = p P
keycode 34 = bracketleft braceleft
keycode 35 = bracketright braceright
keycode 36 = Return
keycode 37 = Control_L
keycode 38 = a A U00103 U00102
keycode 39 = s S U0015f U0015e
keycode 40 = d D
keycode 41 = f F
keycode 42 = g G
keycode 43 = h H
keycode 44 = j J
keycode 45 = k K
keycode 46 = l L
keycode 47 = semicolon colon
keycode 48 = apostrophe quotedbl
keycode 49 = grave asciitilde
keycode 50 = Shift_L
keycode 51 = backslash bar
keycode 52 = z Z
keycode 53 = x X
keycode 54 = c C
keycode 55 = v V
keycode 56 = b B
keycode 57 = n N
keycode 58 = m M
keycode 59 = comma less
keycode 60 = period greater
keycode 61 = slash question
keycode 62 = Shift_R
keycode 63 = KP_Multiply
keycode 64 = Alt_L Meta_L
keycode 65 = space
keycode 66 = Caps_Lock
keycode 67 = F1
keycode 68 = F2
keycode 69 = F3
keycode 70 = F4
keycode 71 = F5
keycode 72 = F6
keycode 73 = F7
keycode 74 = F8
keycode 75 = F9
keycode 76 = F10
keycode 77 = Num_Lock
keycode 78 = Multi_key
keycode 79 = KP_Home KP_7
keycode 80 = KP_Up KP_8
keycode 81 = KP_Prior KP_9
keycode 82 = KP_Subtract
keycode 83 = KP_Left KP_4
keycode 84 = NoSymbol KP_5
keycode 85 = KP_Right KP_6
keycode 86 = KP_Add
keycode 87 = KP_End KP_1
keycode 88 = KP_Down KP_2
keycode 89 = KP_Next KP_3
keycode 90 = KP_Insert KP_0
keycode 91 = KP_Delete KP_Decimal
!keycode 92 = X386Sys_Req
keycode 93 =
keycode 94 =
keycode 95 = F11
keycode 96 = F12
! keycodes 97-107 are not available on 84-key keyboards
keycode 97 = Home
keycode 98 = Up
keycode 99 = Prior
keycode 100 = Left
keycode 101 = Begin
keycode 102 = Right
keycode 103 = End
keycode 104 = Down
keycode 105 = Next
keycode 106 = Insert
keycode 107 = Delete
keycode 108 = KP_Enter
keycode 109 = Control_R
keycode 110 = Pause
keycode 111 = Print
keycode 112 = KP_Divide
!keycode 113 = Alt_R Meta_R
keycode 114 = Break
! keycodes 115-117 are only available on some extended keyboards
! (e.g., Microsoft's ergonomic keyboard).
keycode 115 = Meta_L
keycode 116 = Meta_R
keycode 117 = Menu
!
! Set the modifiers
!
add shift = Shift_L Shift_R
add lock = Caps_Lock
add control = Control_L Control_R
add mod1 = Alt_L
! If you have ServerNumlock set in your XF86Config, you can comment out
keysym Alt_R = Mode_switch
add mod2 = Mode_switch
!
!
!
! If you use any of the special default key mappings in Xconfig, they should be
! duplicated in this file. Mappings should be added before the section above
! which sets the modifiers.
!
! For the key specs:
! LeftAlt => keycode 64
! RightAlt => keycode 113
! AltGr => keycode 113
! ScrollLock => keycode 78
! RightCtl => keycode 109
!
! For the mappings:
! Meta => Alt_L Meta_L
! Alt_R Meta_R
! Compose => Multi_key
! ModeShift => Mode_switch
! ModeLock => Mode_switch X386Mode_Lock
! ScrollLock => Scroll_Lock
! Control => Control_R
!
! If you use ModeShift or ModeLock, the following modifier must be set:
!
!add mod5 = Mode_switch
!
! For example, to get the equivalent of:
!
! ScrollLock ModeLock
! RightAlt ModeShift
! LeftAlt Meta
! RightCtl Compose
!
! use the following:
!
!keycode 78 = Mode_switch X386Mode_Lock
!keycode 113 = Mode_switch
!keycode 64 = Alt_L Meta_L
!keycode 109 = Multi_key
!
!add mod5 = Mode_switch

! When using ServerNumLock in your XF86Config, the following codes/symbols
! are available in place of 79-81, 83-85, 87-91
!keycode 136 = KP_7
!keycode 137 = KP_8
!keycode 138 = KP_9
!keycode 139 = KP_4
!keycode 140 = KP_5
!keycode 141 = KP_6
!keycode 142 = KP_1
!keycode 143 = KP_2
!keycode 144 = KP_3
!keycode 145 = KP_0
!keycode 146 = KP_Decimal
!keycode 147 = Home
!keycode 148 = Up
!keycode 149 = Prior
!keycode 150 = Left
!keycode 151 = Begin
!keycode 152 = Right
!keycode 153 = End
!keycode 154 = Down
!keycode 155 = Next
!keycode 156 = Insert
!keycode 157 = Delete



4. Setare fonturi
În marea lor majoritate, fonturile instalate de xorg suportă UTF-8. Este totuşi recomandat să încărcăm o serie de alte fonturi:

emerge freetype corefonts freefonts
artwiz-fonts sharefonts terminus-font
ttf-bitstream-vera unifont

Apoi modificăm /etc/X11/xorg.conf după cum urmează:
FontPath "/usr/share/fonts/misc:unscaled"
FontPath "/usr/share/fonts/100dpi:unscaled"
FontPath "/usr/share/fonts/75dpi:unscaled"
FontPath "/usr/share/fonts/ttf-bitstream-vera"
FontPath "/usr/share/fonts/corefonts"
FontPath "/usr/share/fonts/Type1"
FontPath "/usr/share/fonts/TTF"
FontPath "/usr/share/fonts/freefont"
FontPath "/usr/share/fonts/artwiz"
FontPath "/usr/share/fonts/sharefonts"
FontPath "/usr/share/fonts/terminus"
FontPath "/usr/share/fonts/unifont"



Din anumite motive, programele de genul xterm au nevoie să fie informate în mod exact care din fonturile din xorg să le folosească. Adăugăm/modificăm următoarea linie în fişierul .Xresources în directorul home curent (dacă este nevoie, creem un fişier nou cu acest nume):
xterm*font: -Misc-Fixed-Medium-R-Normal--20-200-75-75-C-100-ISO10646-1

Trebuie apoi să adăugăm la începutul fişierului .xinitrc următoarele două linii:
xrdb -merge .Xresources
xmodmap .Xmodmap

Cu aceste modificări este timpul să pornim xorg pentru ca setarea de tastatură şi setarea de fonturi să aibă efect. Presupunând că totul a mers bine, deschidem o fereastră xterm iar în această ferestră introducem:
# xterm -u8&

(xterm rulează default fără suport UTF8). O nouă ferestră xterm se deschide, iar aceasta are suportul dorit:
# ãâºþîêÞÎ

O serie de alte emulatore de terminal sub X au suport pentru UTF8, de exemplu rxvt-unicode şi gnome-terminal. Majoritatea comenzilor de tip UNIX suportă utf8, iar ca editoare de text aş menţiona abiword şi gedit.

5. Setare "locale"
Pentru a facilita procesul de internaţionalizare a programelor de calculator, în standardul limbajului C au fost introduse aşa numitele "locales". Implementate ca environment variables, fiecare dintre ele specifică o convenţie privind modul în care un program trebuie să prelucreze un anumit tip de informaţie. Spre exemplu, LC_TIME este folosit pentru a formata timpul potrivit regulilor limbii respective, iar LC_MESSAGES este folosit pentru afişare textelor generate de program (cum ar fi meniurile, help, etc) în limba respectivă.

De menţionat că acestă setare pentru locale este opţională. În cazul în care nu o facem, programele respective vor continua să prelucreze mai departe text românesc fără probleme, dacă au suport iniţial pentru UTF8. Deci, dacă nu ne deranjează meniurile de genul Open/Save/Find, putem sării liniştiţi la capitolul următor.

Începem cu un mic experiment. Într-o fereastră de terminal introducem comanda locale:
# locale
LANG=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=



Dacă arată ca mai sus, înseamnă că variabila locale nu a fost setată încă. Setarea se face în felul următor:
# export LANG=ro_RO.UTF-8
# locale
LANG=ro_RO.UTF-8
LC_CTYPE="ro_RO.UTF-8"
LC_NUMERIC="ro_RO.UTF-8"
LC_TIME="ro_RO.UTF-8"
LC_COLLATE="ro_RO.UTF-8"
LC_MONETARY="ro_RO.UTF-8"
LC_MESSAGES="ro_RO.UTF-8"
LC_PAPER="ro_RO.UTF-8"
LC_NAME="ro_RO.UTF-8"
LC_ADDRESS="ro_RO.UTF-8"
LC_TELEPHONE="ro_RO.UTF-8"
LC_MEASUREMENT="ro_RO.UTF-8"
LC_IDENTIFICATION="ro_RO.UTF-8"
LC_ALL=

O serie întreagă de programe au fost deja traduse în limba română (AbiWord, xmms, gedit, gnome-terminal, etc). Pornite din această fereastră xterm, textul românesc din meniurile programului va fi afişat corect.

6. Pentru programatori
Mesajul de la Bell Labs este deosebit de clar: îl lăsăm pe utilizator să-şi bată capul cu setarea de tastatură şi setarea de fonturi, iar instantaneu o serie întreagă de programe scrise cu mult timp în urmă vor funcţiona corect.
# cat test
Scopul declarat al acestui articol este de a vã lãsa cu impresia cã orice este
posibil, inclusiv sã folosiþi litere precum º ºi þ pe un calculator pe care
tocmai aþi cheltuit o sumã indecentã de bani, ºi care "by default" nu ºtie
decât englezã.
# grep ºtie test
tocmai aþi cheltuit o sumã indecentã de bani, ºi care "by default" nu ºtie
# sed s/ºtie/vrea/ test
Scopul declarat al acestui articol este de a vã lãsa cu impresia cã orice este
posibil, inclusiv sã folosiþi litere precum º ºi þ pe un calculator pe care
tocmai aþi cheltuit o sumã indecentã de bani, ºi care "by default" nu vrea
decât englezã.

Singurul lucru de care trebuie să ţinem cont este ca editorul pe care-l folosim să suporte UTF8:
// file test.c
#include

int main() {
printf("Salut, ºarpe!n");
return 0;
}

gcc este alt program căruia nu-i pasă dacă textul este unicode sau nu:
# gcc test.c
# ./a.out
Salut, ºarpe!
#

No comments:

Post a Comment