[Rio-pm] Problema com formatos

breno breno em rio.pm.org
Domingo Janeiro 27 22:38:26 PST 2013


2013/1/27 Aureliano Guedes <guedes_1000 em hotmail.com>:
> Ola monges,
>
> Estou com uma pasta cheia de arquivos *.psd e um txt usado para modificar o
> nome dos arquivos.
>
> O txt esta da seguinte forma:
> 001#nome_do_arquivo_001
> 002#nome_do_arquivo_002
> 003#nome_do_arquivo_003
> ....
>
> E os arquivos nomeados da seguinte forma:
> nome_do_arquivo_001.psd
> nome_do_arquivo_002.psd
> nome_do_arquivo_003.psd
> ...
>
> O objetivo era renomear os arquivos com base no txt, onde o
> "nome_do_arquivo" fosse substituido pelo numero antes do #.

é sempre um número? Achei curioso tb que vc diz apenas
"nome_do_arquivo" e não "nome_do_arquivo_001". É por acaso, ou no
final de todo nome de arquivo o número que vc quer já vem? (nesse
caso, vc não precisaria de um .txt pra dizer os nomes, basta retirar a
parte em chinês)

> Algo como :
> #!/usr/bin/env perl
>
> use common::sense;
> use autodie;
>
> my @list = <*>;
> @list = glob("*.psd");
>
> open my $in, "<", "nome_do_arquivo.txt";
>
> while (my $line = <$in>){
>     $line = ~/(.+)#´(.+)/;
>     my $s1 = $1;
>     my $s2 = $2;
>
>     foreach my $i (@list){
>         if ($i =~ /.*´$s2/){
>             say "$_: $s2 -> $s1\n";
>             rename $_, $s1;
>         }
>     }
> }
>
> Ou algo parecido.

Muito bom! Seu código melhorou bastante, Aureliano, gostei de ver!
Agora, "ou algo parecido" me assustou. Esse é o código que vc está
usando capaz de reproduzir o seu erro, ou não?

>
> O problema é que que o txt esta gb18030 (Chinês Tradicional) e o Perl
> trabalhando com o charset padrão os bytes são passados sem modificação
> nenhuma.

Tem certeza que é esse o problema? Por quê?

> O sistema consegue converter o nome dos arquivos *.psd e o conteudo do txt
> para iso-8859-1. Dessa forma a leitura fica assim:
>
> 501#°ËÀº»ÔÅ׾Ȱæ#
>

Aparentemente tudo que o sistema conseguiu foi traduzir os bytes pra
algo sem sentido. Qual o encoding do seu terminal? Quando vc faz "ls"
vc vê os nomes dos arquivos adequadamente?

> Em contrapartida se convertido diretamente para utf8 ficaria:
>
> 501#八篮辉抛救版#
>

Como vc fez essa conversão? Esse é só o conteúdo do .txt? E o nome do
arquivo no seu terminal quando faz "ls", fica igual?

> Mas eu creio que o Perl não esteja interpretando o texto original como
> gb18030 e sim como outro formato e tentando converter para utf8.
>

Por quê? O que vc está executando que está gerando um resultado
diferente do esperado? Qual o resultado obtido? warnings? erros?
Adicione alguns "print" no meio do caminho, veja até onde ele está
chegando, veja o conteúdo das variáveis que está usando.

> Portanto não da certo tentar renomear nem mesmo tentar ler o arquivo txt.
>

Ah não? Por quê? O que ele exibe? O que está em "$!" ? O que você
tentou e quais os resultados?

> Alguem tem alguma sugestão de como resolver este problema???
>

Tenho. Nos ajude a te ajudar e tente responder as perguntas que fiz ao
longo desta mensagem. De repente vc até descobre a resposta no
processo! Uma dica, que já te passei antes mas pelo visto vc ainda não
pegou: quebre o seu problema em problemas menores. No seu exemplo tem
um arquivo com nomes de arquivos que estão num sistema e são lidos num
loop e... argh!! Onde está o problema? No arquivo de texto lido? No
loop? Na extração do nome do arquivo alvo? No rename?

Em vez de ficar perdido em meio à tantas variáveis, experimente
reduzir tudo à forma mais simples e crua que representa o que vc
acredita ser o cerne do problema, e tente resolver apenas isso. No seu
caso, que tal colocar o nome de UM dos arquivos hardcoded no seu
programa, que terá apenas uma linha: "rename $velho, $novo". E veja o
que acontece. Observe ainda valores de retorno (perldoc -f rename) e
tente variações (move() do File::Copy em vez do rename, como diz a
documentação do próprio rename). Deu certo? Adicione um pouquinho mais
da complexidade original e tente de novo. Deu erro, pare e observe.
Pergunte se necessário, mas simplifique antes ***sempre***.

Outra dica: se vc está lendo arquivos em um determinado encoding, vc
precisa decodificar os bytes lidos para um formato que o Perl entenda.
Lembre-se que existem 3 encodings em jogo aí: o do seu
sistema/terminal, o do conteúdo do arquivo, e o que o seu programa
está lendo. Por isso, quando se trata de encodings, é muito importante
ter cuidado e ser o mais explícito possível sobre o seu ambiente e
sobre o que está de fato acontecendo.

O módulo canônico para lidar com encodings em Perl chama-se "Encode",
e, para trabalhar com gb18030, vc precisa instalar também o
Encode::HanExtra. Por exemplo (código não testado, fiz no corpo do
email mesmo já que não tenho arquivos em gb18030 nem sei como obter --
aliás, colocar um num pastebin da vida teria ajudado muito, viu? :-)

-------------8<-------------
use 5.16.0;
use warnings;

use Encode;
use Encode::HanExtra;
use autodie;

open my $fh, '< :encoding(gb18030)', 'arquivo_de_texto.txt';

while (my $line = <$fh>) {
   chomp $line;
   say "lendo linha => " . $line;

   if ( $line =~ /(?<num>\d+)#(?<filename>.+)/ ) {
      my $nome_antigo = $+{filename} . '.psd';
      my $nome_novo = $+{num} . '.txt';

      print "tentando renomear de '$nome_antigo' para $nome_novo...";
      if ( rename $nome_antgo, $nome_novo ) {
         say 'FALHA';
      }
      else {
         say 'SUCESSO';
      }
   }
 }
------------->8-------------


Encodings são um pesadelo à parte na vida de muitos programadores,
então se vc está esbarrando com isso vale a pena ler alguns materiais
importantes, como:

"The Absolute Minimum Every Software Developer Absolutely, Positively
Must Know About Unicode and Character Sets (No Excuses!)"
http://www.joelonsoftware.com/Articles/Unicode.html

https://metacpan.org/module/Encode
http://sao-paulo.pm.org/artigo/2010/analisedastecnicasparaabrirelerarquivos
(Solli++)
http://sao-paulo.pm.org/artigo/2011/PERLEUNICODEENTREOUTRASCODIFICACOESDETEXTO
(Stan++)


[]s

-b


Mais detalhes sobre a lista de discussão Rio-pm