Logo SubitoSMS
La soluzione integrata per i tuoi SMS

Unicode, UTF-8
e le altre bestie nere

Autore: Julien Buratto <julien.buratto@linkas.it>
Data: 23/07/04
Versione: 1.5-Uni
Nickname: Thecloud - 홈페이지 바로가기 (Coreano) (dovrebbe apparire circa così: Demo scritta in coreano)
Se li vedi diversi, allora hai proprio bisogno di leggere questo doc :-D

Valid XHTML 1.0!


Introduzione

Questo micro-doc cerca di spiegare in poche righe cosa sono Unicode, UTF-8, come vedere le pagine web in qualsiasi lingua (ma non spiegherò come capirle :-)) e come memorizzare il carattere ф in un database SQL.

Scopo

Brevità e semplicità
(Almeno per le prime 4 pagine, le altre sono un di più).

Disclaimer

Questo documento non vuole essere formale. Il linguaggio cerca di essere semplice, discorsivo e volontariamente impreciso nei contenuti quando, per spiegare sommariamente un concetto, siano necessarie troppe conoscenze 'formali' che possano disturbare la comprensione dell'argomento centrale.


Unicode

Cosa è Unicode

Unicode è una lista di simboli, di disegni e di 'cose mai viste' dette, in modo generico caratteri.

Lo scopo di Unicode

Lo scopo di Unicode è stilare una lista di tutti i caratteri delle lingue del mondo, come i caratteri arabi (ש), le nostre classiche lettere “latine” (a, b, c), i caratteri russi (cirillico: Й), i caratteri greci (Σ) e tutti i caratteri degli altri paesi del mondo

La finalità di Unicode non è legata al solo settore informatico, nel senso che non ha affinità con la programmazione 'per forza'. L'esigenza di Unicode è nata dal voler scrivere documenti leggibili in ogni paese, indipendentemente dal software utilizzato, ma anche dal voler creare una raccolta dei 'caratteri del mondo' completa ai fini della standardizzazione.
Molto utile in tipografia, Unicode vorrebbe risolvere finalmente le problematiche di trasporto di documenti da stampare in paesi diversi.

I set di caratteri

Un esempio per spiegare cosa sono

Se prendessimo un pezzo di carta e ci scrivessimo sopra la parola ciao, così come saremmo abituati a fare in Italia, e prendessimo un aereo verso l'Arabia, potrei far vedere vedere il mio biglietto ad un arabo.

Con questo nuovo amico straniero potrei trovarmi in 3 situazioni:

  1. Lui riconosce i caratteri e li sa leggere, ma non sa che significato abbia la parola ciao (ovvero non capisce che è un saluto) e non sa in quale lingua sia stata scritta (inglese, francese,tedesco ?).

  2. La persona sa leggere la parola e ,dato che conosce l'italiano, sa anche che significato ha la parola ciao (sa, in pratica, che lo stiamo salutando).

  3. La persona non riconosce la parola ciao come una scritta, e per lui potrebbe essere tanto uno scarabocchio quanto un disegno di fantasia; non sapendo neanche in che senso girare 'dritto' il foglio, potrebbe scambiarlo per un insulto (questo è quello che succede spesso a noi con cinese,giapponese e arabo, etcetc).

Una persona che ha sottomano Unicode ha la conoscenza che ha la persona del caso 1, ovvero riconosce la parola ciao (sarebbe meglio dire che riconosce i 4 caratteri) come una parola formata da caratteri esistenti. È anche in grado di dire in che tipo di SET è stata scritta quella parola (Latin) ma non sa in che lingua è scritta (potrebbe essere, per lui, una parola inglese, tedesca, francese...etc etc).

Uscendo dalla metafora

Detto in modo 'meno esemplificativo', un set di caratteri è un elenco di caratteri che alcune lingue utilizzano per scrivere.

Tutte le lingue (o quasi) di origine latina o con parti di essa (francese, italiano, inglese, tedesco, etc etc) usano i caratteri del set Latin.
Ci sono poi paesi con lingua di origine latina che usano questi caratteri ma anche altri (Extended Latin) tipo questi: Ě ĝ ě (in italiano non esistono parole con questi caratteri, tanto per capirci e neppure i latini le usavano).

L'encoding informatico dei caratteri

Un esempio per spiegare cosa sono

Mettiamo caso che io voglia scrivere il carattere ф e lo voglia mettere in un testo al computer.

Questo simbolo fa parte del SET dei caratteri del Cirillico (in pratica lo usano i russi, per scrivere nella loro lingua).

Nel caso in cui io volessi visualizzare questo carattere su un computer che non ce l'ha sulla tastiera (quindi non posso premere il tasto relativoҖ) mi trovo nel dilemma di come fare a metterlo nel testo.

Beh 'a mano con la penna' è facile copiare un carattere... coi computer invece bisogna mettersi daccordo per fare in modo che i tasti che si premono corrispondano ai caratteri che vengono visualizzati (a quanti è capitato di premere è e veder comparire ] ).
Con i computer bisogna mettersi daccordo e definire un modo il più universale possibile per evitare questi problemi in modo che, su qualsiasi computer io vada, per visualizzare quel carattere, io possa usare sempre la stessa procedura.
Se per esempio ci diamo la regola che il carattere Җ corrisponde al 4096-esimo carattere, e quello successivo è il җ (4097) allora se voglio scrivere il primo dei due caratteri, dovrò usare il suo codice 4096.

Come poi inserire questo carattere nel testo in modo efficace, è un problema diverso, ma spesso i programmi di uso comune spiegano come inserire un carattere Unicode conoscendone il codice (ad esempio OpenOffice ha il menu Inserisci-Carattere speciale).

Se si usa Unicode è buona norma mettere U+ davanti al codice (U+4096) per far capire di quale elenco stiamo facendo uso.

PS: Si vedrà in seguito che 4096 non è il 4096-esimo carattere ma l'unione di 40 e 96 e che hanno un significato particolare in Unicode.

Uscendo dalla metafora

Per 'encoding' si intende una regola matematica che permette di calcolare un codice corrispondente ad ogni carattere. Per i comuni mortali, l'encoding si concretizza in una semplice tabella che mostra, per ogni carattere, il suo codice corrispondente.
Ogni encoding ha spesso una tabella diversa (ma nel tempo si è cercato di tener buone quelle vecchie estendendole (cioè allungandole) con i nuovi caratteri introdotti mano a mano.

Encoding diversi: per cosa si differenziano ?

Abbiamo notato tutti che ci sono un sacco di Encoding diversi vero ? Ecco perchè ho scritto questo documento-nocumento :-D Per capirci meglio.

Esempio

Inventiamoci un nostro set di caratteri, piccolo piccolo, e chiamiamolo Example.
Il set Example è formato dai caratteri a b c (che ci siamo inventati anch'essi)
Ora inventiamoci un encoding per i caratteri del Set Example e chiamiamolo Encoding-1

Carattere

Codifica numerica in Encoding-1

a

97

b

98

c

99

In pratica abbiamo 'inventato' 3 caratteri (a b c) e gli abbiamo associato un numero come a noi più garbava. In particolare abbiamo scelto, senza motivo, i numeri 97 98 99.

Domanda

Potevamo associare, al posto dei numeri 97 98 e 99 altri numeri diversi, o un codice tipo A97 A98 e A99 ?

Risposta

Certo che sì.

Sarebbe stato un encoding diverso, dello stesso set di caratteri, nulla vieta di farlo.

Riassumendo

  1. Due encoding sono diversi se associano, allo stesso carattere, un codice diverso;

  2. Due encoding sono diversi se hanno set di caratteri diversi (uno il cinese e uno il Latin)

  3. Due encoding possono essere diversi se usano modalità di associazione diverse (al posto di associare un numero, ad esempio, associano una lettera+un numero, due lettere, etc etc) (Più o meno la stessa cosa del punto 1).

Lo stato di cose: Unicode e UTF-8

Ora che abbiamo più o meno detto cosa sono i set di caratteri (una lista di caratteri), cosa è l'econding (l'algoritmo matematico che serve a memorizzare i codici dei caratteri), definiamo quale è lo scopo di Unicode.

Lo scopo di Unicode è:

  1. Fare una lista con tutti i caratteri del mondo;

  2. Suddividerli per 'tipologia linguistica' (Latino, Ebreo, Cirillico) o per tipologia (simboli, segnali, etc etc);

  3. Dare un nome esteso ad ogni carattere:

    Ad esempio: “Above – Combining Double Vertical Line” è il nome di un carattere che sta sopra alle lettere (come un accento), ed è formato da due barrettine verticali parallele, sembra un doppio apice. (il suo codice Unicode è U+030E e visivamente è  ̎ mentre il doppio apice è “ );

  4. Dare un codice per ogni carattere:

Ad esempio: Il carattere a ha codice Unicode U+0061.

Ma per noi cosa è importante conoscere ?

Conoscere l'encoding UTF-8 a noi non è assolutamente utile.
Ci è utile invece conoscere quali sono i caratteri Unicode (vedi sito Unicode.org);
Ci è utile sapere quale encoding il nostro computer (software o engine SQL o browser) utilizza perchè conoscendo quale encoding stiamo usando potremo capire se stiamo guardando le cose in modo corretto.

Se io guardo un testo codificato in modo diverso da quello che usa il mio computer, non si vedranno i caratteri (o magari se ne vedranno solo alcuni).

Esempio

Se un sito è stato scritto da un cinese di Taiwan, questo potrebbe utilizzare due tipi di caratteri:

Nel primo caso, Big-5, la pagina web potrà avere testi 'Latin' (francese,inglese, etcetc) e cinese tradizionale, ma non di altre lingue orientali.

Una pagina Unicode UTF-8 può contenere scritte inglesi, Cinesi, Giapponesi, Ebree, Arabe, etc nella stessa pagina.
Questo perchè il Big-5 contiene anche i Latin ma non altre lingue orientali.

Come mai tutti i cinesi non usano UTF-8 ?

A sentire alcuni rappresentanti taiwanesi, Big-5 contiene caratteri del cinese tradizionale che UTF-8 non ha (Non potendo io stesso verificare, se è una bufala, vi ho avvisato!).
Per quanto riguarda i giapponesi, pare che non sia la stessa cosa.

Concludendo

poiché:

  1. Nessuno tranne Unicode ha fatto una lista sei set di caratteri disponibili così completa;

  2. Unicode è un organizzazione per la standardizzazione dei caratteri;

  3. Lo standard Unicode è usato dalle major e si sta diffondendo su tutte le piattaforme;

  4. UTF-8 è lo standard di codifica più diffuso;

Conviene usare anche noi UTF-8 in qualsiasi occasione.


Da qui in poi, ci sono dei contenuti aggiuntivi.
Consiglio di leggere quest'ultimo paragrafo per risolvere i piccoli problemi quotidiani.


Alcuni casi comuni in cui usare Unicode

Problema

  1. La visualizzazione di pagine web straniere;

  2. La realizzazione di pagine web;

  3. La memorizzazione di dati su server SQL;

  4. La creazione di file XML;

  5. Inviare e visualizzare bene il carattere € Euro con Outlook (nota su The Bat);

  6. Vedere i quadratini al posto dei caratteri speciali..

Soluzioni

  1. Nel browser, selezionando la Codifica Unicode – UTF e non la Codifica Occidentale (Latin o Window). Di solito questo viene fatto in automatico dal browser su pagine che contengano una intestazione di encoding specifica.

  2. Impostare il charset UTF-8 (si veda il tag meta content-type, content e chaset tipo charset="UTF-8") nella pagina html.
    Attenzione: lo standard prevede l'uso di UTF-8 e non di utf-8 o utf8 o UTF8 oppure UTF_8.
    Es: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />;
    Es 2. Aggiungere AddType text/plain;charset=UTF-8 txt al proprio webserver, se possibile.
  3. In SQL usare colonne che memorizzino i char con il set UTF-8 o avviare il server in modalità UTF-8.
    MySQL, dalla versione 4.1 ha ampliato la gestione dei caratteri e delle regole di passaggio da un encoding all'altro (collate).
  4. Specificare sempre nel file XML, nella XML declaration, encoding=”UTF-8” (oppure la UTF-16).
    Nel corpo del file XML tutti i caratteri dovranno essere sostituiti da entity della UTF corrispondente o nella sua rappresentazione numerica nel caso in cui il carattere non sia presente sulla tastiera. Se il simbolo 'speciale' è presente sulla tastiera può essere usato tranquillamente a meno dei caratteri speciali & > < “ ' .
    Si tenga presente che i parser XML sono tenuti, per essere considerati standard, a leggere e interpretare le entity UTF-8 e UTF-16 e non altre entity che possono essere spesso utilizzate.
    Piccola nota: UTF-16 occupa più bit per essere rappresentato, quindi per trasferire un file in rete ci vorrà più tempo di UTF-8 (o al meglio lo stesso tempo)
  5. In Outlook Express è possibile modificare le opzioni sia di lettura che di invio dei messaggi Email. Per leggere i messaggi, in Opzioni-Lettura c'è il menu per cambiare l'encoding di lettura, e per inviare messaggi UTF-8 basta entrare nella tab Invio e selezionare Impostazioni internazionali.
    Inoltre quando si manda una email con il simbolo €, impostando un encoding che supporta il simbolo Euro, non verrà più visualizzato il messaggio di errore che dice che state cercando di inviare il messaggio con un encoding che non supporta il simbolo usato. Questo perchè l'editor di Outlook Express è Unicode mentre le email inviate non è detto che lo siano, quindi prima di inviare una mail OE la converte nell'Ecoding prescelto. Se i caratteri usati nel corpo (Unicode) non sono tutti codificabili nell'encoding prescelto, OE si lamenterà.
    The Bat pare non avere un composer Unicode.
  6. La cosa più banale del mondo, ma... la font che stai usando che per visualizzare il testo in questione, è una font Unicode ? Sembra sciocco, ma non tutti i caratteri sono inseriti nelle font; questo si solito causa la visualizzazione di un carattere 'strano' come questo □ al posto del carattere atteso.
    Io mi sono trovato, in questo documento, a dover cercare, cambiando la font nel menu Inserisci-carattere speciale, una font che avesse la tabella completa Unicode dei caratteri. Poichè per le TTF ci sono dei diritti e la distribuzione non è permessa, si può installare (in windows ad esempio) l'Arial Unicode MS dalla suite di Office (installando il supporto multilingue).

HTML e caratteri speciali

Se in una pagina web si vuole inserire qualche carattere speciale, ci sono tre soluzioni:

Esempio

Per inserire il carattere < si può usare:

NB: Le entity sono definite come & Name ; (http://www.w3.org/TR/REC-xml#sec-references)

HTML 4.0

Attualmente HTML 4.0 ha le entity name per ogni carattere del set Latin-8859-1 più alcuni aggiuntivi, tra cui il simbolo Euro.

Conoscevi solo amp, lt, gt, quot ? Ecco ora sai che ce ne sono un sacco!

I Numeri degli Encoding

Ecco alcuni esempi per capire la potenza di vari Encoding

UTF-8

UTF-8 può occupare spazi diversi per memorizzare caratteri diversi, in particolare:

UTF-16

UTF-16 memorizza tutti i primi 65536 caratteri in 2 byte, gli altri in 4 byte.

UCS-2

UCS-2 rappresenta solo i primi 65536 caratteri Unicode e occupa sempre 2 byte.

UCS-4

Tutti i caratteri sono rappresentati a 4 byte e per ora tutti sono rappresetanbili.

Open Office 1.1.0 e Macromedia Dreamweaver

Per scrivere questo documento sto usando OpenOffice 1.1.1 e ringrazio per lo stupendo prodotto.

Per quanto riguarda Unicode, non mi è stato però possibile inserire tutti caratteri Unicode in modo semplice e dal menu Inserisci-Carattere speciale perchè non sono presenti tutti i caratteri del set Unicode in modo indipendente dalla font. Ovvero, per inserire un carattere bisogna scegliere un font adatto.

L'help di OO defisce Unicode come:

Unicode è un sistema per in grado di gestire i caratteri e gli elementi che compongono tutti i tipi di carattere e i sistemi di caratteri noti. Ogni carattere o elemento viene espresso con un numero di due byte. ...(continua)”.

Per quanto riguarda la versione HTML sto usando Macromedia Dreamweaver MX 2004 con update.

I problemi di unix

Programmazione

L'ordine è alfabetico nel caso qualcuno mi chiedesse perchè parlo prima di Coldfusion e poi di Php.

C

Il C ha come unità di rappresetantazione del carattere 'char' il byte di 8bit.

Sono state però aggiunte delle librerie per i wide-char (wchar_t) ad esempio che possono essere usate per risolvere il problema della trattazione dei caratteri estesi.

Coldfusion

Supporta UTF-8 anche nel codice, così come esemplificato qui sotto:

<cfprocessingdirective pageencoding="utf-8">
<cfset ک=ArrayNew(1)>

(code by Giampaolo Bellavite)

Java

In modo completo, Java può utilizzare i caratteri Unicode anche nel codice. Quindi i programmatori russi possono usare i caratteri cirillici per scrivere sorgente java e compilarlo. Inoltre ha tanti stream per trasferire carattere e convertire, contemporaneamente i carattere nei vari encoding.

public class ClasseEsempio {
String città;
String perchè;

Perl

In Perl si può usare la dichiarazione 'use UTF-8' . Per convertire caratteri vi sono le classi Unicode.

Php

Php: ci sono tante funzioni per la conversione di codifica dei caratteri, ma non vi è (pare ci sia nella versione 5) un pieno supporto ai caratteri Unicode internamente. Nella visualizzazione, Php altro non deve fare che inviare i caratteri al browser, quindi mi chiedo perchè io ne stia parlando qui :-D

Python

Attualmente supporta caratteri Unicode.

Usare Unicode con Linux e la consolle

Non spiegherò come fare, ma servono la tastiera impostata in modo corretto (si veda l'howto sulla tastiera e lingua italiana), e si deve usare una font per consolle Unicode (ocio a kbd)

L'encoding UTF-8

Questa parte era messa prima, ma data la “complessità” e l'inutilità dell'argomento, è stata spostata in fondo.

Trattiamo il carattere che abbiamo visto nell'esempio di prima, a il cui codice Unicode è U+0061.

UTF-8 è un modo per dare un numero alle cose, e usa un numero variabile di byte per ogni codice di carattere. U+0061 occupa, nella rappresentazione UTF-8 la bellezza di 1 byte mentre ם ne occupa 2.

Nella rappresentazione ASCII il carattere a occupava 1 byte (il codice ASCII 61) espresso con 8 bit 00111101.

Da ASCII a UCS-2

Per poter avere un codice per ogni carattere, sono stati, col tempo, introdotti sempre nuovi tipi di codifica dei caratteri (come si è fatto cambiando le targhe delle auto in Italia per avere nuovi numeri disponibili) spesso allungando il numero di cifre usate per rappresentarli tutti.

Da ASCII a UCS-2 si è arrivati aggiungendo un nuovo blocco esadecimale davanti a quello già esistente e proseguendo nella numerazione (passando da 0xHH a 0xHH 0xJJ).

In UCS-2 la lettera a si rappresenta con 0061 (0x00 aggiunta 0x61 originale ASCII). (Ovvero due byte, 0 e 169, pari a 00000000 e 00111101).

NB: Il carattere 0x61 della lettera a siamo abituati a chiamarlo ASCII 97 che è la sua forma numerica con base 'decimale' e non 'esadecimale' nell'Encoding dei caratteri ASCII a 8 bit.

Da UCS-2 a UTF-8

Per problemi di compatibilità con alcuni sistemi Unix e per poter rappresentare molti più caratteri si è arrivati a UTF-8 (vedi infondo per i problemi)

UCS-2 assegnava due byte (0x00 e 0x61), UCS-4 con lo stesso sistema di estensione ne usava 4.

UTF-8 associa un numero variabile di byte quindi occupa meno memoria.

Esempio di encoding UTF-8

Il carattere © (il suo nome in Unicode è “Copyright Sign”) ed è rappresentabile col codice Unicode U+00A9

Il suo corrispondente in notazione UCS-2 occupa 2 byte da 8 bit, 00 00 00 00 1010 1001 (0x00-0xA9).
Per capirci: 8 bit 00 00 00 00 sono 1 byte, 1010 1001 sono 1 altro byte. 00000000 è il 0x00 e 10101001 è l'esadecimale A9 (che si scrive 0xA9).

La sua rappresentazione decimale ASCII è 169 (ovvero basta convertire quel numero binario in base decimale).

Il suo corrispondente UTF-8 si ottiene aggiungendo 0xC2 (11000010). (*)

11 00 00 10 + 10 10 10 01 = 0xC2 + 0xA9

(*) Per capire come mai aggiungere C2 e non un'altra cosa, si veda dopo e si faccia riferimento alla RFC 2279 che spiega l'algoritmo matematico che sta dietro a UTF-8.

Ad esempio, coi caratteri come questo (ASCII decimale 169), compresi tra 128 e 2047 si deve usare la maschera per le sostituzioni

110 ??? ?? 10 ??????

Mettendo al posto degli ??? i bit del numero da convertire partendo da destra e mettendo degli 0 dove ci son degli spazi vuoti: 110 00010 10 101001.
Qui si vede la maschera riempita con tre zeri in grassetto e i bit sottolineati son quelli dell'esadecimale del carattere 0xA9.
Questa è la rappresentazione interna al nostro computer del carattere © in modalità UTF-8.

Per capirci meglio, a voce, non si usa la rappresentazione dei caratteri Unicode in UTF-8 ma si usa il codice Unicode in formato esadecimale UCS-2 come U+00A9.
PS: Per vedere le maschere corrispondenti, digitare su linux man 7 UTF-8 oppure guardare la RFC 2279

Da approfondire

Trovo possa essere interessante ricercare il significato del numero 8 che compare in UTF-8. Con Giampaolo Bellavite (giampaolo@bellavite.com) si è supposto che sia:

Riferimenti:

Ringraziamenti:

Chen (Family Name)

Unicode(UTF-8): 9673

Big-5: B3AF

MEI (Middle Name)

Unicode(UTF-8): 6885

Big-5: B1F6

Yuh (First Name)

Unicode(UTF-8): 7389

Big-5: A5C9