Lettere straniere in Python

Una sequenza di lettere fenicie casuali, ottenuta con Python, ma visualizzabile in Word solo impostando il font giusto. C'è un effetto simile sul fondale di uno spettacolo di Aldo, Giovanni e Giacomo, durante lo sketch del corso di lingue straniere. Le lettere sono quelle dell'alfabeto fenicio, ma nel loro caso sono ruotate di 90 gradi. 


Ricordo che anni fa per manipolare stringhe di lettere straniere in Python dovetti fare una certa fatica. Questo perché, mentre le lettere latine che usiamo noi occupano un byte in memoria, quelle di altri alfabeti ne possono occupare di più, ma l'interprete comunque operava un byte alla volta. 

Non ricordo come risolsi il problema. Mi sembra di ricordare che mettendo una u davanti alla stringa, prima delle virgolette, si poteva lavorare con le singole lettere anziché con i singoli byte. 

All'epoca ogni utente era abbandonato a sé stesso e doveva consultare varie pagine di documentazione e forum specializzati alla ricerca delle soluzioni. 

Oggi c'è l'intelligenza artificiale che fornisce le risposte sul momento. Ma saranno quelle giuste?

Provo a chiedere a Copilot. L'intelligenza artificiale della Microsoft mi spiega che effettivamente il problema c'era ai tempi di Python 2 ed è stato superato con Python 3. 

Con Python 2 impostando un ciclo for per stampare ciascuna lettera di una parola l'interprete agiva sui singoli byte. Con una parola in inglese, ad esempio "hello", non c'erano problemi, perché ad ogni lettera corrisponde a un byte, ma con una parola scritta in un altro alfabeto, ad esempio il greco, il risultato era un nonsense. 

Mettendo una b prima delle virgolette all'inizio della stringa, i byte venivano presi con il loro valore numerico. Quindi la sequenza "ABC" dava come risultato tre valori, 65,66 e 67, che sono i codici Unicode associati a queste tre lettere. 

Con una stringa contenente la parola greca κόσμος, che si legge "kosmos" e significa "mondo", venivano fuori dodici numeri: 206, 186, 207, 140, 207, 131, 206, 188, 206, 191, 207, 130. Sono sei lettere, quindi due byte per lettera. se li leggiamo a coppie, notiamo che il primo byte è sempre 206 o 207. Questo perché il metodo ingegnoso inventato per la codifica Utf-8 è che è il valore del byte che dice al sistema se deve va considerato o insieme a uno o più byte di continuazione oppure se è esso stesso un byte di continuazione. 

I valori minori di 128 vanno letti da soli: ad esempio 65 è la A maiuscola. I valori da 192 a 223 vanno letti con un byte successivo, ed è proprio il caso che si verifica con 206 e 207. I numeri da 128 a 191 sono i byte di continuazione, com'è appunto il caso dei numeri di questa sequenza che si trovano nelle posizioni pari. 

Esistono altri valori di inizio che implicano due o tre byte di continuazione, a seconda. 

In pratica quando il programma trova il numero 206 non prende la lettera numero 206 ma è come se andasse alla tabella chiamata "206" a prendere la lettera numerata come indicato dal byte successivo.

Sto cercando di semplificare il tutto per chi non è programmatore, senza entrare nel dettaglio del significato dei singoli bit. 

In pratica, chiedendo al computer di stampare ciascuna lettera greca della parola "kosmos", i byte 206 sarebbero stati interpretati come una I con accento circonflesso, i byte 207 sarebbero stati interpretati come una I con una dieresi (due puntini affiancati, in alto), e gli altri byte sarebbero stati interpretati come simboli speciali: il simbolo del grado, quello del 3/4 o un punto interrogativo capovolto. 

Questo perché l'interprete andava ad attingere lettere sulla base della tabella ISO-8859-1, o comunque quella che era impostata di default con il sistema in uso. 

La soluzione poteva essere quella di scrivere la stringa sotto forma di stringa Unicode, ovvero con la u prima delle virgolette di apertura. Oppure, avendo già una stringa di byte, si poteva codificarla in Unicode col metodo .decode, passando come argomento "utf-8". 

Con Python 3 le normali stringhe sono già in formato Unicode. 

Quando è stato introdotto Python 3?

La data del rilascio è stata il 3 dicembre del 2008, racconta ancora Copilot. "Python 3 ha impiegato anni per diventare lo standard, perché molti progetti erano ancora legati a Python 2. Solo nel 2020, con la fine del supporto ufficiale a Python 2.7, Python 3 è diventato universalmente adottato". 

Insomma, solo 5 anni fa. 

Per ottenere in Python 3 lo stesso output che si sarebbe ottenuto con Python 2 basta codificare la stringa un Utf-8. Iterando normalmente vengono fuori i valori numerici di ogni byte, mentre per vedere le lettere corrispondenti basta convertirle in caratteri con la funzione chr(). 

Questa funzione non si aspetta in input il valore del singolo byte ma quello della lettera. 

Cioè: Unicode ha assegnato a ogni lettera un valore univoco, che viene poi smistato in un certo numero di byte a seconda della codifica scelta. In Utf-8 le lettere latine occupano un byte mentre quelle cinesi ne occupano tre, in Utf-16 sia le une che le altre occupano due byte. Questo è scomodo per i testi in inglese, che occupano il doppio della memoria, ma è comodo per quelli in cinese, che occupano il 33% in meno. 

Quindi se a chr() passo dei valori minori di 128, la funzione restituisce le normali lettere e i simboli contenuti nella codifica Ascii, o la relativa sequenza di escape se non sono visualizzabili. 

Coi numeri da 128 in poi, la funzione chr() inizia a restituire simboli di valuta, frazioni e lettere accentate, che se convertite in Utf-8 danno una sequenza di 2 byte.

Più aumentiamo il valore dell'argomento e più vediamo lettere con i diacritici più strani e lettere sconosciute. 

Arrivando a 913 riconosciamo la lettera alfa maiuscola, a cui seguono nelle posizioni successive le altre lettere dell'alfabeto greco: beta, gamma, delta...

Il massimo valore Unicode che può essere assegnato è U+10FFFF in esadecimale, ossia il numero 1.114.111. 

Dice Copilot che finora i valori assegnati sono solo 150.000, non necessariamente in ordine ma in base a un'organizzazione basata su piani. La maggior parte dei caratteri comuni ha valori compresi tra U+0000 e U+FFFF (Basic Multilingual Plane, BMP), altri si trovano nei piani supplementari, numerati da 1 a 16, che comprendono emoji, caratteri storici, simboli matematici, eccetera. 

Si potrebbe pensare che è possibile visualizzare in Python qualunque carattere conoscendone il valore Unicode. Non è proprio così. La lettera alf dell'alfabeto fenicio ad esempio ha il code-point 67840. Però se passo questo argomento alla funzione chr() nell'interprete mi compare un rettangolino vuoto (tofu). Questo non significa che il computer non abbia capito di quale carattere si tratta: semplicemente non ha trovato nei font conosciuti al sistema uno che contenga la forma di questa lettera. Si tratta di un alfabeto che non si usa più da parecchi secoli, quindi il supporto non è ritenuto necessario nei sistemi operativi moderni. 

Se copio questo rettangolino e lo incollo in Blocco Note, assume la forma di un rettangolino con un punto interrogativo al suo interno. Se la incollo in Word, ottengo di nuovo un rettangolino vuoto, in Times New Roman. Ma se lo converto in Segoe UI Historic, ecco comparire la lettera della forma giusta, una specie di A ruotata di 90 gradi in senso antiorario. 

Quindi, anche se di default non posso visualizzare parole fenicie nella shell o in blocco note, comunque posso facilmente eseguire operazioni su un testo fenicio che poi vado a visualizzare in Word usando il font giusto. 

Ad esempio, se voglio una sequenza random di 100 lettere dell'alfabeto fenicio, posso creare una stringa vuota e aggiungerci 100 volte il risultato della funzione chr(random.randint(67840,67871), dove i parametri in questione sono il minimo e massimo valore Unicode delle lettere dell'alfabeto fenicio. Stampo a video il risultato, lo copio e lo incollo in Word convertendolo nel font adatto, come Segoe UI Historic, se ce l'ho, o Noto Sans Phoenician che si può scaricare gratuitamente da Google Fonts (come Tuffy, che però è meno attraente). 

Domanda: se uno non è uno studioso di storia antica cosa se ne fa di una schermata piena di lettere fenicie casuali, che comunque non significano niente? Beh, può usarla a scopi decorativi. E' quello che hanno fatto Aldo, Giovanni e Giacomo in un loro spettacolo, quando nello sketch sul corso di lingue in cui Aldo si mette a gridare a raffica frasi in dialetto siciliano, fanno proiettare sul fondale una serie di lettere fenicie, ruotate di 90 gradi, solo per suscitare la sensazione di una lingua straniera incomprensibile. 

Nel Segoe UI Historic ci sono anche geroglifici o caratteri cuneiformi. Su tutti i computer ci sono font che supportano i migliaia di caratteri della lingua cinese. 

Commenti

Post più popolari