Distinguir ascii de caracteres UTF-8 no mesmo arquivo

0

No Ubuntu 18.04, criei um arquivo de texto fictício com apenas um caractere UTF-8 è,. Os outros caracteres são todos ascii:

$ cat dummytext
Hello
Helloè

Este é o resultado hexdump:

$ hexdump -C dummyfile
00000000  48 65 6c 6c 6f 0a 48 65  6c 6c 6f c3 a8 0a        |Hello.Hello...|
0000000e

O arquivo é identificado como

$ file dummyfile
dummyfile2: UTF-8 Unicode text

Cada caractere é representado por um único byte, exceto o ècaractere UTF-8 , que é c3a8, portanto, é representado por 2 bytes. Como o conteúdo do arquivo pode ser interpretado corretamente, se o número de bytes usados ​​para representar cada caractere não for constante?

Meu palpite: talvez o analisador, ao encontrar um valor hexadecimal maior que o último asciicaractere 7F(e este é o caso de c3), seja obrigado a ler pelo menos outro byte, para determinar o caractere correto a ser impresso?

BowPark
fonte
Eu acho que você não expressou completamente a pergunta que pretende fazer. Sua pergunta parece realmente ser duas: Como filesaber que isso é UTF-8, quando poderia ser uma codificação antiga de 8 bits? seguido por Como um decodificador UTF-8 sabe onde as seqüências de bytes múltiplos começam e terminam? .
JdeBP 21/03
@JdeBP Talvez, inconscientemente, as perguntas reais tenham sido as que você escreveu (mesmo que eu tenha usado apenas filecomo uma verificação adicional). A resposta de DopeGhoti se encaixa na segunda. Para o primeiro, talvez fileprocure bytes "cujo bit de ordem superior esteja definido" e, em seguida, seja capaz de adivinhar se há uma codificação UTF-8.
BowPark 21/03

Respostas:

3

No manual do BSD, seção 5, a página em UTF8 lê:

DESCRIÇÃO

A codificação UTF-8 representa caracteres UCS-4 como uma sequência de octetos, usando entre 1 e 6 para cada caractere. É compatível com ASCII, então 0x00- 0x7freferem-se ao conjunto de caracteres ASCII.

A codificação multibyte de caracteres não ASCII consiste inteiramente em bytes cujo bit de ordem superior está definido. A codificação real é representada pela seguinte tabela:

 [0x00000000 - 0x0000007f] [00000000.0bbbbbbb] -> 0bbbbbbb
 [0x00000080 - 0x000007ff] [00000bbb.bbbbbbbb] -> 110bbbbb, 10bbbbbb
 [0x00000800 - 0x0000ffff] [bbbbbbbb.bbbbbbbb] ->
         1110bbbb, 10bbbbbb, 10bbbbbb
 [0x00010000 - 0x001fffff] [00000000.000bbbbb.bbbbbbbb.bbbbbbbb] ->
         11110bbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
 [0x00200000 - 0x03ffffff] [000000bb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
         111110bb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
 [0x04000000 - 0x7fffffff] [0bbbbbbb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
         1111110b, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb

Se mais do que uma única representação de um valor existe (por exemplo, 0x00; 0xC0 0x80; 0xE0 0x80 0x80), a representação mais curto é sempre utilizada. Os mais longos são detectados como um erro, pois representam um risco potencial à segurança e destroem o mapeamento de sequência de caracteres 1: 1: octeto.

No manual do Linux, seção 7, a página no UTF8 lê da mesma forma:

DESCRIÇÃO

[... UTF-8 é situacionalmente melhor que o UCS-2 em parte porque, além disso, a maioria das ferramentas UNIX espera arquivos ASCII e não pode ler palavras de 16 bits como caracteres sem grandes modificações. [...]

A codificação UTF-8 de Unicode e UCS não apresenta esses problemas e é a maneira comum pela qual o Unicode é usado em sistemas operacionais no estilo UNIX.

Propriedades

A codificação UTF-8 possui as seguintes boas propriedades:

  • Os caracteres UCS 0x00000000para 0x0000007f(os caracteres clássicos US-ASCII) são codificados simplesmente como bytes 0x00para 0x7f(compatibilidade ASCII). Isso significa que arquivos e seqüências de caracteres que contêm apenas caracteres ASCII de 7 bits têm a mesma codificação em ASCII e UTF-8.

Portanto, não é realmente possível distinguir ASCII de UTF-8 porque, em um arquivo UTF-8, ASCII é UTF-8. fileexamina os primeiros 96 KB de um arquivo e tenta determinar o que é. Como ele vê mais de zero seqüências de código UTF-8, determina que o arquivo seja UTF-8 porque é um superconjunto estrito de ASCII.

DopeGhoti
fonte
Obrigado. No Ubuntu não existe a mesma página de manual. O homólogo está na seção 7, e não é tão conciso e claro quanto o seu, que pode ser encontrado no FreeBSD .
BowPark 21/03
Adicionei uma citação semelhante no manual do Linux (7) para acompanhar o manual do BSD (5).
DopeGhoti 21/03
Muito obrigado!
BowPark 21/03