Perl Brasil

Pesquisar

Documentação

Planeta

Eventos

Comunidade

r3 - 22 Jan 2008 - AlceuJunior

Como ler arquivos codificados em UTF-16

Problema

Você está tentando ler um arquivo texto codificado em UTF-16 mas está recebendo mensagens de aviso com "wide character" mesmo já tendo informado que o arquivo está codificado em UTF-16.

Solução

A implementação do Perl para lidar com UTF-16 desconsidera a presença de BOM (Bit Order Mark) no início do arquivo. É necessário ler os dados sem codificação nenhuma (raw) e depois convertê-los para UTF-16.

Discussão

Ao tentar ler arquivos em UTF-16, você recebe mensagens de aviso (warnings) dizendo que está lidando com caracteres que não podem ser representados/convertidos. Isso acontece mesmo se for utilizado algo como o código abaixo:

open(my $entrada, '<:utf16LE', $arquivo) or die "Não consigo ler arquivo $arquivo: $!";

Mesmo indicando o BOM, seu programa insiste em reclamar de não conseguir converter um caracter. Isso vai ocorrer sempre porque Perl não consegue lidar automaticamente com o caracter BOM, localizado no início do arquivo. Comparações e expressões regulares também vão falhar com a leitura da primeira linha.

Para resolver isso, é necessário ler o arquivo em forma binária utilizando a camada raw da seguinte forma:

open(my $entrada, '<:raw', $arquivo) or die "Não consigo ler arquivo $arquivo: $!";

Isso resolve o problema com o BOM, que é descartado neste caso. Mas o perl (o interpretador) ainda precisa saber como converter os caracteres para a representação correta, então é necessário decodificar os caracteres como UTF-16. Isso poderia ser feito convertendo os dados linha à linha, mas é possível concatenar camadas de leitura na abertura do arquivo da seguinte forma:

open(my $entrada, '<:raw:encoding(UTF-16)', $arquivo) or die "Não consigo ler arquivo $arquivo: $!";

Isso resolve completamente o problema, ao menos para leitura do arquivo. Para escrever arquivos também em UTF-16LE é necessário especificar a utilização do BOM da seguinte maneira:

open (my $saida, '>:raw:encoding(UTF-16LE)', $arquivo) or die "Não consigo criar $arquivo: $!";
print $saida $texto;
close $saida;

Mais informações em perldoc perluniintro.

Comentários