$ locale charmap
UTF-8
Nel mio ambiente attuale, il set di caratteri è UTF-8, ovvero i caratteri sono codificati da 1 a 4 byte per carattere (anche se, poiché la definizione originale di UTF-8 consentiva il codice carattere punta fino a 0x7fffffff, la maggior parte degli strumenti riconoscerebbe UTF- Sequenze di 8 byte fino a 6 byte).
In quel set di caratteri, sono disponibili tutti i caratteri di Unicode, a a
è codificato come valore di byte 65, a 乕
come 3 byte 228 185 149 e é
come sequenza di due byte 195 169 per esempio.
$ printf 乕 | wc -mc
1 3
$ printf a | wc -mc
1 1
Adesso:
$ export fr_FR.iso885915@euro
$ locale charmap
ISO-8859-15
Ho modificato il mio ambiente, dove il set di caratteri ora è ISO-8859-15 (sono state modificate anche altre cose come lingua, simbolo di valuta, formato della data, la raccolta di quelle impostazioni internazionali viene definita locale ). Ho bisogno di avviare un nuovo emulatore di terminale in quell'ambiente per adattare il rendering dei suoi caratteri alla nuova locale.
ISO-8859-15 è un set di caratteri a byte singolo, il che significa che ha solo 256 caratteri (in realtà anche meno di quelli effettivamente coperti). Quel particolare set di caratteri viene utilizzato per le lingue dell'Europa occidentale in quanto copre la maggior parte delle sue lingue (e il simbolo dell'euro).
Ha il a
carattere con valore di byte 65 come in UTF-8 o ASCII, ha anche il é
carattere (come comunemente usato in francese o spagnolo per esempio) ma con il valore di byte 233, non ha il carattere 乕.
In quell'ambiente, wc -c
e wc -m
darà sempre lo stesso risultato.
In Ubuntu come sulla maggior parte dei moderni sistemi simili a Unix, il valore predefinito è solitamente UTF-8 in quanto è l'unico set di caratteri supportato (e codifica) che copre l'intera gamma Unicode.
Esistono altre codifiche di caratteri multi-byte, ma non sono così ben supportate su Ubuntu e devi passare attraverso i cerchi per essere in grado di generare un locale con quelli, e se lo fai, scoprirai che molte cose non lo fanno lavorare bene.
Pertanto, in effetti su Ubuntu, i set di caratteri sono a byte singolo o UTF-8.
Ora, qualche altra nota:
In UTF-8, non tutte le sequenze di byte formano caratteri validi. Ad esempio, tutti i caratteri UTF-8 che non sono ASCII sono formati con byte che hanno tutti l'ottavo bit impostato, ma dove solo il primo ha il settimo bit impostato.
Se si dispone di una sequenza di byte con l'ottavo bit impostato, nessuno dei quali ha il settimo bit impostato, ciò non può essere tradotto in un carattere. Ed è allora che stai iniziando ad avere problemi e incongruenze poiché il software non sa cosa farne. Per esempio:
$ printf '\200\200\200' | wc -mc
0 3
$ printf '\200\200\200' | grep -q . || echo no
no
wc
e grep
non trovi personaggi lì dentro ma:
$ x=$'\200\200\200' bash -c 'echo "${#x}"'
3
bash
trova 3. Quando non è in grado di mappare una sequenza di byte su un carattere, considera ogni byte un carattere.
Può diventare ancora più complicato in quanto in Unicode ci sono punti di codice che non sono validi come caratteri e alcuni che non sono caratteri e, a seconda dello strumento, la loro codifica UTF-8 può o non può essere considerata come un carattere.
Un'altra cosa da prendere in considerazione è la differenza tra personaggio e graphem e come sono resi.
$ printf 'e\u301\u20dd\n'
é⃝
$ printf 'e\u301\u20dd' | wc -mc
3 6
Lì, abbiamo codificato 3 caratteri come 6 byte resi come un graphhem, perché abbiamo 3 caratteri combinati insieme (un carattere di base, un accento acuto combinato e un cerchio che racchiude).
L'implementazione GNU di wc
come si trova su Ubuntu ha un -L
interruttore per dirti la larghezza di visualizzazione della linea più ampia nell'input:
$ printf 'e\u301\u20dd\n' | wc -L
1
Scoprirai anche che alcuni personaggi occupano 2 celle in quel calcolo di larghezza come il nostro 乕
personaggio dall'alto:
$ echo 乕 | wc -L
2
In conclusione: nella parola selvaggia byte, carattere e graphem non sono necessariamente gli stessi.