$ locale charmap
UTF-8
No meu ambiente atual, o conjunto de caracteres é UTF-8, ou seja, os caracteres são codificados com 1 a 4 bytes por caractere (embora, como a definição original do código de caracteres permitido UTF-8 permita pontos até 0x7fffffff, a maioria das ferramentas reconhecerá UTF- Sequências de 8 bytes de até 6 bytes).
Nesse conjunto de caracteres, todos os caracteres do Unicode estão disponíveis, a a
é codificado como valor de byte 65, a 乕
como os 3 bytes 228 185 149 e é
como a sequência de dois bytes 195 169, por exemplo.
$ printf 乕 | wc -mc
1 3
$ printf a | wc -mc
1 1
Agora:
$ export fr_FR.iso885915@euro
$ locale charmap
ISO-8859-15
Eu modifiquei meu ambiente, onde o conjunto de caracteres agora é ISO-8859-15 (outras coisas como idioma, símbolo da moeda, formato da data também foram modificados, a coleção dessas configurações regionais é conhecida como localidade ). Preciso iniciar um novo emulador de terminal nesse ambiente para adaptar sua renderização de caracteres ao novo local.
ISO-8859-15 é um conjunto de caracteres de byte único, o que significa que ele possui apenas 256 caracteres (na verdade, menos ainda do que o que é realmente coberto). Esse conjunto de caracteres específico é usado para os idiomas da Europa Ocidental, pois abrange a maioria dos idiomas (e o símbolo do euro).
Ele possui o a
caractere com valor de byte 65, como em UTF-8 ou ASCII, também possui o é
caractere (como normalmente usado em francês ou espanhol, por exemplo), mas com o valor de byte 233, não possui o caractere 乕.
Nesse ambiente, wc -c
e wc -m
sempre dará o mesmo resultado.
No Ubuntu, como nos sistemas mais modernos do tipo Unix, o padrão geralmente é UTF-8, pois é o único conjunto de caracteres (e codificação) suportado que cobre todo o intervalo Unicode.
Existem outras codificações de caracteres de vários bytes, mas elas não são tão bem suportadas no Ubuntu e você precisa passar por obstáculos para poder gerar um código de idioma com elas; caso contrário, verá que muitas coisas não trabalhe corretamente.
Portanto, no Ubuntu, os conjuntos de caracteres são de byte único ou UTF-8.
Agora, mais algumas notas:
No UTF-8, nem todas as seqüências de bytes formam caracteres válidos. Por exemplo, todos os caracteres UTF-8 que não são ASCII são formados com bytes que possuem o oitavo bit definido, mas onde apenas o primeiro possui o sétimo bit definido.
Se você tiver uma sequência de bytes com o oitavo bit definido, nenhum dos quais com o sétimo bit definido, isso não poderá ser convertido em um caractere. E é aí que você começa a ter problemas e inconsistências, pois o software não sabe o que fazer com elas. Por exemplo:
$ printf '\200\200\200' | wc -mc
0 3
$ printf '\200\200\200' | grep -q . || echo no
no
wc
e grep
não encontre nenhum personagem lá, mas:
$ x=$'\200\200\200' bash -c 'echo "${#x}"'
3
bash
encontra 3. Quando não pode mapear uma sequência de bytes para um caractere, considera cada byte um caractere.
Pode ficar ainda mais complicado, pois há pontos de código no Unicode que são inválidos como caracteres e alguns que não são caracteres e, dependendo da ferramenta, sua codificação UTF-8 pode ou não ser considerada como um caractere.
Outra coisa a ser levada em consideração é a diferença entre caráter e grafema, e como eles são renderizados.
$ printf 'e\u301\u20dd\n'
é⃝
$ printf 'e\u301\u20dd' | wc -mc
3 6
Lá, codificamos 3 caracteres com 6 bytes renderizados como um graphem, porque temos 3 caracteres combinados (um caractere base, um sotaque agudo combinado e um círculo anexo).
A implementação GNU wc
encontrada no Ubuntu possui uma -L
opção para informar a largura de exibição da linha mais larga na entrada:
$ printf 'e\u301\u20dd\n' | wc -L
1
Você também descobrirá que alguns caracteres ocupam 2 células nesse cálculo de largura, como nosso 乕
personagem acima:
$ echo 乕 | wc -L
2
Em conclusão: na palavra mais selvagem, byte, caractere e graphem não são necessariamente os mesmos.