Pages

Tuesday, May 02, 2006

Convertendo arquivos UTF-8 em ISO-8859-1

[update]
Esse tópico recebeu uma versão atualizada. Embora esse aqui continue correto e completamente funcional. A versão atualizada contém mais informações e agrega o conteúdo gerado pelos comentários desse tópico até a data de publicação daquele tópico.
[/update]

Recentemente tive alguns problemas com codificação de alguns arquivos e do próprio sistema (algumas coisas ainda não resolvidas, mas isso é outro assunto!).

O fato é que tive que fazer uma pesquisa sobre como converter um tipo de arquivo em outro. O que me impressionou não foi a dificuldade de achar uma solução, mas a complexidade de algumas soluções que eu encontrei. Pensei que certamente tal complexidade não seria necessária e estava certo !

Encontrei uma dica no rodapé do site das FunçõesZZ ensinando justamente como converter o arquivo das FunçõesZZ, que é escrito em ISO-8859-1, em UTF-8.

O comando é muito simples: iconv
Faz parte da libc6, ou seja, todo mundo têm instalado, e possuí sintaxe simples.

iconv -f codificacao_de_origem -t codificacao_de_saida arquivo

Assim para converter UTF-8 para ISO-8859-1 temos:

iconv -f utf-8 -t iso-8859-1 arquivo

Para o contrário utilizamos:

iconv -f iso-8859-1 -t utf-8 arquivo

É necessário redirecionar a saida de arquivo para algum lugar, algo como:

iconv -f utf-8 -t iso-8859-1 arquivo > novo_arquivo

Sendo assim, eu acrescentei ao meu ~/.bashrc* as seguintes linhas

alias iso2utf='iconv -f iso-8859-1 -t utf-8'
alias utf2iso='iconv -f utf-8 -t iso-8859-1'

Agora quando eu quiser converter um tipo de arquivo em outro, eu só preciso usar o iso2utf ou o utf2iso

Agora, por que tanta desinformação sobre assunto ? É tão fácil converter um tipo em outro, é tão simples !

[update]
O Marcelo Oliveira escreveu um belo script para fazer a conversão em lote e o colocou aqui, nos comentários.
O script apresenta o cuidado de não modificar seus arquivos originais, produzindo uma cópia dos mesmos em outros diretórios. Modificar o comportamento do script para converter arquivo iso-8859 para utf-8 é trivial (pelo menos para quem leu o tópico até aqui). Um detalhe importante é que o script não suporta caminhos ou nomes que contenham espaços (Posso estar enganado, mas o Marcelo deve ter utilizado esse script em um diretório de dados para internet onde espaços não são comuns e arquivos de imagem são.).
Marcelo, eu e a galera agradecemos a iniciativa e a colaboração!
[/update]

37 comments:

  1. Tive o mesmo problema e resolvi da mesma maneira. Pena que ainda assim alguns acentos ficaram errados como o "É". Ainda estou trabakhando nisso... E assim achei seu blog! :)

    ReplyDelete
  2. Pois é, encontrei um programa chamado recode, apt-get install recode no Ubuntu. Só ficou errado agora o "É". Todo o resto está ok...

    ReplyDelete
  3. "Agora, por que tanta desinformação sobre assunto ? É tão fácil converter um tipo em outro, é tão simples!"
    Esta conversão é algo realmente simples e utilíssimo para quem tem problemas com acentuação, seja no HTML, seja em banco de dados MySQL quando faz migrações (como é o meu caso).
    No entanto, mesmo sendo algo muito simples, o único site que fala sobre isto é este.
    Apenas é necessário tomar cuidado no caso de caracteres especiais que dão erro na conversão utf2iso como alguns traços (os mais longos) ou algumas aspas especiais (francesas).

    ReplyDelete
  4. De fato, os caracteres que só existem em UTF-8 não são convertidos. Bem notado.

    []'s

    ReplyDelete
  5. Anonymous2/5/07 17:44

    Pelo contexto, estou entendendo que a conversão é realizada no conteúo do arquivo texto. Ou se trata da conversão no nome do arquivo?

    ReplyDelete
  6. Ooops!!!
    Desculpe a demora.

    Sim... o texto se refere apenas ao conteúdo do arquivo. Não ao nome.

    Para modificar o nome, existem vários aplicativos prontos, mas se pode até usar o mesmo conceito dentro de um script.

    ReplyDelete
  7. Quando eu comecei a usar o iconv com mais freqüência, também defini "iso2utf" e "utf2iso" em meu bashrc, e ainda por cima com os mesmos nomes. O iconv é ótimo, mas ficar digitando esses parâmetros o tempo todo é um atraso de vida!

    ReplyDelete
  8. São os nomes mais intuitivos do mundo...

    ReplyDelete
  9. Anonymous26/6/07 06:40

    O iso2utf tem problema de nao incluir o BOM ("Byte Order Mark") no ficheiro. O ficheiro em formato UTF deve comecar com bytes EFBB (hex). Alquem tem resolvido este?
    Tare

    ReplyDelete
  10. Se isso é um problema, nunca percebi qualquer erro ...

    Mas recentemente eu "li" gente dizendo que o iconv era ultrapassado. Pode até ser, mas ainda é o melhor. Se substituto, o recode, ainda apresenta erros.

    []'s

    ReplyDelete
  11. Marcelo Oliveira4/7/07 17:23

    Obrigado pelas informações.
    Ajudarem muito a resolver meu problema, que era converter todos os arquivos de uma determinada pasta e subpastas de utf-8 para iso-8859-1.

    Para isso escrevi um script que chamei de um nome super original: utf2iso.sh =)

    segue abaixo o fonte.
    -----
    #!/bin/bash

    # 04/07/2007
    # por Marcelo Oliveira - www.iboletim.com.br
    # Licença de uso: GPL

    # uso:
    # utf2iso.sh diretorio-a-ser-convertido

    # fecha se nao for fornecido nenhum argumento
    if [ $# -eq 0 ]
    then
    echo "ERRO: especifique o nome da pasta com os arquivos a serem convertidos!"
    echo "Uso: ./utf2iso.sh diretorio-a-ser-convertido"
    exit 1

    fi

    # cria diretorio para armazenar arquivos convertidos
    cp -R $1 iso-8859-1

    # acessa diretorio com os arquivos a serem convertidos
    cd $1

    # cria lista de todos os arquivos que serao convertidos (estou excluindo .gif e .jpg)
    lista=`find -type f | grep -v gif | grep -v jpg`

    # executa conversao
    for i in $lista
    do
    echo "convertendo... $i"
    iconv -f utf-8 -t iso-8859-1 $i > ../iso-8859-1/$i;
    #read; # para verificar as mensagens de erro
    done

    if [ $? == 0 ]
    then
    echo -e "\nConversao terminada com sucesso!\n"
    fi
    -----

    ReplyDelete
  12. Boa, Marcelo,
    sua contribuição será, certamente, muito útil para muita gente.
    Obrigado !

    Como eu sei que tem gente que não lê até aqui, eu vou chamar a atenção para o script no corpo do tópico.

    Abraços.

    ReplyDelete
  13. Marcelo Oliveira9/7/07 17:33

    Mitre,

    Fico feliz em saber que será útil, assim com o seu post foi pra mim.
    Realmente fiz esse script para converter um plugin do Joomla e não me preocupei com essa questão dos espaços...

    Abraço.

    ReplyDelete
  14. Marcelo, sabe como eu tive o palpite da sua intenção ? Pela linha:

    find -type f | grep -v gif | grep -v jpg

    Que tipo de aplicação você converte o conteúdo recursivamente e exclui esses dois tipos de imagem ? Sites ...

    Abraços !

    ReplyDelete
  15. Caro Mitre,

    Por estes dias andei baixando umas músicas no computador do meu irmão, ele é bitolado na porcaria do windows e as músicas estão com caracteres "ç é" e coisas do tipo.

    Pesquisei aqui
    e econtrei um script, além de ter testado as funões zz, acho que as mesmas carecem de uma função zziconv não acha?

    ReplyDelete
  16. Sérgio,
    vamos separar dois problemas aqui. O primeiro é o de codificação dos nomes, o segundo é o windows.

    Há um problema com alguns nomes de arquivos vindos do windows que são irrecuperáveis. Eu não faço idéia do porque isso ocorre, mas que ocorre, ocorre.

    Dito isso, voltamos ao script. Sim, alguma coisa nesse assunto. Mas falta, antes de tudo, um jeito de descobrir qual é a formatação atual do conteúdo do arquivo. Não tem como saber isso por comando. Imagina como seria perigoso popularizar um script que não consegue identificar o tipo atual de codificação antes de converter ?

    A outra coisa é sobre as funções ZZ, você viu o último anúncio do Aurélio ? Ele tem aversão ao utf-8 e a própria precisa de conversão antes de ser usada em sistemas utf8.

    Mas o maior problema é a identificação da codificação atual, como saber se o arquivo atual é X ou Y (ou Z, ou etc ...) ?

    []s

    ReplyDelete
  17. Conversão de ISO-8859-1 para UTF-8 em C++ utilizando iconv:

    string toUtf8(const string &input)
    {
    const char *inptr = input.c_str();

    char outbuf[input.length() * 2 + 1];
    char *outptr = (char *) outbuf;
    memset(outptr, 0, input.length() * 2 + 1);

    size_t inbytes_left = input.length();
    size_t outbytes_left = input.length() * 2;

    iconv_t cd = iconv_open("UTF-8", "ISO-8859-1");
    if (cd == (iconv_t)(-1)) {
    printf("\n\nConversao nao suportada!\n");
    return "";
    }

    int count = iconv(cd, &inptr, &inbytes_left, &outptr, &outbytes_left);

    if (count < 0) {
    if (errno == E2BIG) {
    printf("\n\nErro (%d): Vetor de saida muito pequeno!\n", errno);
    } else if (errno == EILSEQ) {
    printf("\n\nErro (%d): Sequencia invalida de caracteres!\n", errno);
    } else if (errno == EINVAL) {
    printf("\n\nErro (%d): Sequencia incompleta de caracteres!\n", errno);
    } else {
    printf("\n\nErro (%d): Nao identificado!\n", errno);
    }

    return "";
    }

    string output = (string) outbuf;
    return output;
    }

    ReplyDelete
  18. Rafael, bom, muito bom mesmo e obrigado. Ainda não testei, mas provavelmente você me passou um pedaço de código que me será muito útil no futuro. Obrigado.

    ReplyDelete
  19. O único problema desse tipo de conversão é que se houverem arquivos já no formato UTF-8, eles serão convertidos novamente, o que corromperá o arquivo. Infelizmente o ICONV não é lá muito inteligente e não verifica se o arquivo já está no formato final ou não...

    ReplyDelete
  20. Edemilson,

    você conhece algum software de terminal que saiba me dizer qual é a codificação de um certo arquivo ?

    Infelizmente eu não conheço nenhum. Já procurei muito, especialmente porque queria adicionar essa inteligência ao sistema, mas ...

    Abraços.

    ReplyDelete
  21. E aí, Mitre, beleza?
    Lá vou eu ressuscitar tópico!

    Nas minhas andanças pelo google em busca de informações sobre codificação de caracteres, descobri o seu blog, e consequentemente, o script do Marcelo. Ao editar o script para usar em meu sistema, descobri um aplicativo interessante que provavelmente já está por padrão instalado na distro que eu uso (Ubuntu 8.04): o utf8tolatin1.

    Consultando a man page do utf8tolatin1, descobri que ele faz exatamente aquilo que eu precisava, e funciona.

    Tem outro aplicativo, muito util por sinal, que serve pra fazer exatamente o que você precisa, o file, normalmente localizado em /usr/bin/file. É só dar um which file que você encontra. Ele serve pra identificar o tipo de arquivo do argumento que é passado pra ele, não apenas arquivos de texto. simplesmente digite "file nome-do-arquivo" e ele vai dizer, se for arquivo de texto, a codificação dos caracteres do mesmo.


    Espero ter ajudado!

    Abraços!

    ReplyDelete
  22. Bob, esse é um dos tópicos mais lidos do blog...

    Qualquer informação adicional que seja colocado aqui certamente ajudará alguém...

    Sua informação, no mínimo, vai ajudar a mim, e muito.

    Agora que sei que posso descobrir qual é a codificação de um arquivo com

    file --mime-encoding texto.txt

    eu tenho um mundo aberto. Muito obrigado.

    Aliás, esse tópico necessita de uma repaginada, porque é muito importante manter a informação dele atualizada.

    Um exemplo disso é o utf8latin1 que comentou, eu não conheço (ou pelo menos não me lembro sobre) esse script/programa, mas vou verificar.

    Na época que eu escrevi esse tópico, o ubuntu ainda não oferecia uma conversão para o conteúdo dos arquivos, apenas para o nome dos arquivos e não checava para ver se ele havia sido convertido antes, de forma que não era possível rodar o programa duas vezes.

    É bom saber que não deixaram de atualizar essa necessidade.

    Um abraço e obrigado.
    J. F. Mitre

    ReplyDelete
  23. E aí, tudo bem?

    Update do comentário.

    Esta aqui é a man page do programa que eu mencionei no comentário anterior: http://linux.die.net/man/1/utf8tolatin1

    E este é o código-fonte do cidadão: http://tiny.cc/utf8tolatin1

    E agora que eu li de novo este tópico, percebi que já tem 3 anos que você postou isto, o que mostra que problemas com diferentes codificações de caracteres ocorrem há muito tempo e com muita frequência.

    Esta é a maravilha do software livre: todo mundo se ajuda, e cada um contribui como pode.

    Abraços!

    P.S.: Se houver problemas com os links, bobandiara arroba gmail ponto com.

    ReplyDelete
  24. Muitíssimo obrigado por essa iniciativa. Parabéns.

    ReplyDelete
  25. Aqui o script já modificado para converter somente os arquivos textos em utf-8

    Façam bom proveito!

    #!/bin/bash

    # 04/07/2007
    # por Marcelo Oliveira - www.iboletim.com.br
    # modificado por Benneh Carvalho - www.sempirataria.wordpress.com
    # Licença de uso: GPL

    # ATENÇÃO: Um detalhe importante é que o script não suporta caminhos ou nomes que contenham espaços

    # uso:
    # utf2iso.sh diretorio-a-ser-convertido

    # fecha se nao for fornecido nenhum argumento
    if [ $# -eq 0 ]
    then
    echo "ERRO: especifique o nome da pasta com os arquivos a serem convertidos!"
    echo "Uso: ./utf2iso.sh diretorio-a-ser-convertido"
    exit 1

    fi

    # cria diretorio para armazenar arquivos convertidos
    cp -R $1 iso-8859-1

    # acessa diretorio com os arquivos a serem convertidos
    cd $1

    # cria lista de todos os arquivos utf-8 que serao convertidos
    lista='file --mime-encoding *.txt | grep utf-8'

    # executa conversao
    for i in $lista
    do
    echo "convertendo... $i"
    iconv -f utf-8 -t iso-8859-1 $i > ../iso-8859-1/$i;
    #read; # para verificar as mensagens de erro
    done

    if [ $? == 0 ]
    then
    echo -e "\nConversao terminada com sucesso!\n"
    fi
    -----

    Um Abraço a todos!

    Benneh Carvalho
    sempirataria.wordpress.com

    ReplyDelete
  26. Amigos, sei que tudo que foi explicado aqui refere-se a Linux, mas alguém conhece alguma solução para a que conversão seja realizada no Windows? Por favor não me crucifiquem estou apenas buscando informação, como disse o amigo ali em cima, no único site que encontrei que fala a respeito do assunto. Obrigado a todos!

    ReplyDelete
  27. Anderson,
    você pode instalar o cygwin que é um porte de algumas ferramentas linux para o windows, mas não sei se vai fazer o que você quer ... teria que testar (ou esperar que alguém comente aqui algo do tipo).

    você pode instalar o vim para o windows (o vim é um editor bem poderoso típico do linux, mas possui versão nativa no windows), que certamente lhe dará acesso a esse tipo de solução (embora eu não tenha certeza se isso seria algo simples). Outra solução de programa seria instalar o KDE no windows, assim, você teria acesso a programas como o Kate/Kedit que resolveriam o seu problema.

    Se não tiver muito espaço em HD, pode até experimentar o linux em um live CD através de um VirtualBox ou VMWare da vida. Por não precisar de instalar nada, consome pouco espaço (apenas a instalação do Virtualbox) e resolve o problema com razoável eficiência (se souber alguma coisa sobre o uso do Virtualbox e o mínimo conhecimento do uso do Linux ou de paciência para aprender sobre o mesmo).

    O que eu não sei é se existe uma solução simples para esse problema dentro do windows apenas.

    Já sofri muito com esse problema quando arquivos disponibilizados via rede Samba vinham para o meu computador e sem cerimônias estavam com codificação totalmente diferente. Felizmente, era eu que usava o Linux, então eu não tinha problemas. De fato, esse problema data da época que criei esse tópico.

    ReplyDelete
  28. rapaz... agora que percebi que fui coveiro do post hehehe obrigado pela sugestão... consegui utilizando o Ubuntu, não imaginava que fosse tão simples a instalação e utilização do Linux!!

    ReplyDelete
  29. Bem, esse é o tópico mais visitado do meu blog e o mais comentado também. Desde 2006, em todos os anos, ele recebeu comentários, adições etc e tal.

    Inclusive, eu já criei um tópico mais recente sobre o assunto (revivendo o texto base e acrescentando novas informações com base nos comentários...), mas o Google conhece esse aqui melhor do que o novo...

    Para quem não tem aversão a computadores e possui uma pequena vontade de aprender, o Linux é bem simples.

    ReplyDelete
  30. Obrigado pelo post. Hoje você me salvou fazendo uma conversão de um banco de dados de iso8859-1 para utf-8...

    ReplyDelete
  31. Anonymous27/9/10 15:26

    Ola, qual seria um comando para saber se meu arquivo esta codificado em UTF-8 ou ISO88591. Uso CentOS 5.5

    ReplyDelete
  32. file --mime-encoding nomedoarquivo

    Verifique a versão atualizada do texto que também foi escrito nesse blog para mais informações.

    ReplyDelete
  33. Um comando para verificar o tipo de codificação de um arquivo seria:
    file -i arquivo | awk -F ';' '{print $2}';

    ReplyDelete
  34. Esse post salvou minha vida, muito obrigada! =)

    ReplyDelete
  35. Muito bom o artigo, já tive esse problema algumas vezes, agora ficou bem mais facil resolver! Obrigado

    ReplyDelete
  36. Encontrei esse tópico que foi bastante útil.

    Acontece que a variável $lista fica com algo do tipo:
    nome1.txt: utf-8
    nome2.txt: utf-8

    E isso causa erros em iconv.

    Corrigi a filtragem da seguinte maneira:

    lista=`file --mime-encoding *.txt | grep utf-8 | cut -d: -f1'

    Dessa maneira a variável conterá apenas o nome do arquivo, sem o separador e sem o tipo do arquivo.

    ReplyDelete
  37. Nossa, nunca imaginei que poderia ser tão simples. Obrigado!

    ReplyDelete