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.
