[Rio-pm] Isso não deveria estar certo???

Aureliano Guedes guedes_1000 em hotmail.com
Sábado Dezembro 8 02:13:53 PST 2012


Breno++, eu precisei mover esse e-mail para pasta "importantes" assim como fiz com aquele ultimo que me ajudou. 
Dicas assim não se pode deixar perder.

Lerei sim os links que me passou. E sim, a duvida foi respondida. E não recebei como bronca, nem fiquei chateado ou algo do tipo.

Não sei o que dizer alem de: "Obrigado".

> Date: Sat, 8 Dec 2012 03:40:15 -0200
> From: breno em rio.pm.org
> To: rio-pm em pm.org
> Subject: Re: [Rio-pm]	Isso não deveria estar certo???
> 
> Oi Aureliano,
> 
> cara, antes de tudo, parabéns. O exemplo que vc colou no email mostra
> que vc está prestando atenção no que é dito aqui na lista. Seus
> códigos estão agora com strict (faltou só o 'warnings', hein?), usando
> autodie, open com 3 argumentos, muito bom mesmo! Agora, pra ficar
> perfeito, falta só uma coisa: por favor, antes de mandar dúvidas,
> lembre que as pessoas daqui da lista não estão sentadas aí do seu lado
> olhando o seu problema, nem vivendo o seu dia-a-dia para saber os
> motivos e objetivos do código, tampouco possuem (eu pelo menos não
> possuo) poder de ler mente :-)
> 
> Por exemplo, quando vc pergunta algo do tipo:
> 
> > Monges, cade o erro???
> 
> Fica faltando o clássico grupo: "o que vc está tentando fazer, de modo
> geral? No código específico, o que deveria estar acontecendo mas não
> está? Ainda no código específico, o que está de fato acontecendo em
> vez do que deveria?"
> 
> Quando, mesmo depois do Junior Moraes matar a charada, vc continua com:
> 
> > Mas me diz uma coisa, como editar um arquivo.
> 
> A gente tem que se esforçar até pra saber que é uma pergunta, mais
> ainda qual é a real pergunta por trás da pergunta. "Como editar um
> arquivo" é quase tão vago quanto "Preciso saber o que estou errando
> aqui" (retirado de outra thread que vc começou). Percebe o padrão?
> 
> Isso não é uma bronca. Mas, pensa comigo: se der a impressão que vc
> não está se esforçando nem pra fazer a pergunta, pq alguém se
> esforçaria pra te dar a resposta? A atividade na lista é voluntária e
> não remunerada, feita por pessoas com um interesse em comum (Perl) e
> que se dispõem a ajudar umas às outras em seu tempo livre. Por isso
> mesmo, se vc quer respostas melhores e mais rápidas, precisa nos
> ajudar a te ajudar! Por exemplo, experimente ler suas perguntas em voz
> alta antes de enviar o email, e veja se elas deixam realmente claro o
> que você está perguntando. Existe um texto muito bom sobre isso
> chamado "Como fazer perguntas inteligentes" mas também é grande e tem
> muitas coisas lugar-comum que você certamente já sabe. Se me permite a
> sugestão, vá direto nessas aqui, que são onde (eu pelo menos) sinto
> mais dificuldade:
> 
> http://www.istf.com.br/perguntas/#writewell
> http://www.istf.com.br/perguntas/#beprecise
> http://www.istf.com.br/perguntas/#symptoms
> http://www.istf.com.br/perguntas/#goal
> http://www.istf.com.br/perguntas/#examples
> 
> Não estou falando isso pra vc ficar chateado, pelo contrário! Estou só
> tentando te ajudar a nos ajudar, e assim tirar maior proveito das
> listas e melhorar cada vez mais. Os parágrafos acima são uma leitura
> super rápida, pense como um investimento: vc vai gastar menos de 5
> minutos pra ler (e está traduzido em português!) e se prestar atenção
> nesses pontos, tenho certeza que daqui pra frente você vai conseguir
> respostas muito mais rapidamente nessa e em qualquer outra lista!
> 
> Dito isso, deixa eu tentar te ajudar. Eu *acho*, depois de perder um
> bom tempo olhando pro seu exemplo, que a sua pergunta é:
> 
> "Pessoal, como eu faço pra abrir o mesmo arquivo tanto para leitura
> quanto para escrita?"
> 
> ou
> 
> "Pessoal, como eu faço para ler e escrever no mesmo arquivo, ao mesmo tempo?"
> 
> 
> Se for isso mesmo, é uma pergunta super comum. E, como a maioria das
> coisas em Perl, há mais de uma maneira de se fazer :)
> 
> Digamos, para efeito de exemplo, que você queira passar o nome de um
> arquivo como parâmetro para o seu programa. O arquivo tem o formato:
> 
> ----------8<-----------
> >blablabla
> ACTGAACAGTAGCTACTGACTCGTACGCTCGTAGC
> >lalalala
> CAGCTGATCGATCGTAGCATGCTACG
> ---------->8-----------
> 
> E o que você quer é transformar esse arquivo em algo como:
> 
> ----------8<-----------
> >contig0
> ACTGAACAGTAGCTACTGACTCGTACGCTCGTAGC
> >contig1
> CAGCTGATCGATCGTAGCATGCTACG
> ---------->8-----------
> 
> Claro, não só duas linhas e sim centenas, mas acho que deu pra entender.
> 
> 
> Solução 1 (one-liner)
> ================
> 
> perl -i -pe 'BEGIN { $i = 0 } $i++ if s{^>.+$}{>contig$i}' arquivo.txt
> 
> Essa solução usa perl como ferramenta para transformação de arquivos
> "in place". O "-pe" executa o código entre aspas para cada linha do
> arquivo passado, imprimindo o que estiver em $_ no final do
> processamento de cada linha. O código em si é simples: substitua
> "^>.+$" (início de linha seguido de ">" seguido de qualquer coisa,
> seguido do fim da linha) pela string ">contig$i", onde $i é um número
> que começa com zero (por isso o BEGIN { $i = 0 }, senão $i começa
> vazio, e a primeira linha vira apenas ">contig" em vez de ">contig0").
> Sempre que conseguir fazer essa substituição (ou seja, sempre que a
> linha em questão casar com a regex do lado esquerdo do s{}{}),
> incremente o valor de $i. Assim, quando a linha casar com a regex, a
> substituição sera feita, o $i será incrementado, e a linha será
> impressa (por causa do "-p"). Se a linha não casar com a regex, nada
> será feito e a linha será impressa sem mudanças (de novo, por causa do
> "-p").
> 
> Executando apenas com o "-pe", ele vai imprimir na tela o resultado
> pra vc. Isso significa que vc pode redirecionar pra outros arquivos,
> se quiser. Mas como em nosso problema queremos que o próprio arquivo
> seja modificado, usamos a opção "-i" (de "in place"), que escreve a
> saída no próprio arquivo de entrada pra você, sem que você precise
> ficar se preocupando com criação e cópia de arquivos temporários. Se
> quiser manter o original para fins de backup, basta trocar "-i" por
> "-i.bak", e o perl manterá uma cópia do original em "arquivo.txt.bak".
> 
> Mais detalhes: perldoc perlrun
> 
> 
> 
> Solução 2 (one-liner, em arquivo)
> ==========================
> 
> ----------8<-----------
> #!/usr/bin/env perl -pi
> BEGIN { $i = 0 }
> $i++ if s{^>.+$}{>contig$i}
> ---------->8-----------
> 
> One-liners são bacanas, mas são também difíceis de manter e de
> lembrar. Uma alternativa é copiá-los para arquivos que podem ser
> executados normalmente. Sabe o "shebang", aquela linha com "#!" que
> chama o "perl"? Você pode passar parâmetros por ela também. No caso,
> estamos passando "-p" e "-i" juntos ("-pi"), já que não precisamos do
> "-e" pois o código está no próprio arquivo. Repare também que o "-i"
> tem que ser o último parâmetro (sem nada depois), pois se
> escrevessemos "-ip" o perl vai achar que vc quer editar o arquivo e
> gravar um backup com extensão "p".
> 
> Claro que um "one-liner em arquivo" é difícil de manter, porque vc tem
> que prestar atenção nos modificadores passados (em nosso caso, "-pi")
> e fazer a "tradução" de cabeça do que de fato está acontecendo. Também
> tem que, idealmente, adicionar strict, warnings, declarar variáveis,
> aquilo tudo que é imprescindível para um programa profissional e fácil
> de manter. Para contornar esse problema, você pode procurar soluções
> como o App::Rad para converter seus one-liners em programas, ou
> simplesmente continuar lendo :)
> 
> 
> 
> Solução 3 (alteração in-place, versão extendida)
> =====================================
> 
> ----------8<-----------
> #!/usr/bin/env perl
> use strict;
> use warnings;
> 
> # para mudar arquivos 'in-place'
> # vindos do ARGV.
> local $^I = q{};
> 
> my $i = 0;
> while ( my $linha = <ARGV> ) {
>   if ($linha =~ s/^>.+$/>contig$i/ ) {
>     $i++;
>   }
> }
> continue {
>   die "erro editando arquivo in-place: $!\n"
>     unless print $linha;
> }
> ---------->8-----------
> 
> Essa versão é a forma "extendida" do one-liner. Acho legal ver como
> uma simples linha se transforma dessa forma, dá outra perspectiva para
> quanto o perl facilita a nossa vida (outra comparação que sempre me
> impressiona é Moose x OO tradicional, mas isso é outro papo). A
> primeira coisa a notar é que estamos inicializando a variável local
> $^I, uma variável especial do Perl que transforma os arquivos de
> entrada nos próprios arquivos de saída, exatamente como o "-i" faz na
> linha de comando. Colocamos a string vazia pois, nesse exemplo, não
> estamos gravando backup do original. Depois, lemos o conteúdo dos
> arquivos linha-a-linha e fazemos nossa já conhecida substituição e
> incremento do $i (dessa vez botei o if na forma "ativa", pra mostrar
> que tanto faz: vale o que ficar mais claro para você). Finalmente,
> termos o bloco "continue", que é executado no final de cada linha.
> Poderíamos ter escrito nosso while sem o continue, assim:
> 
> ----------8<-----------
> while ( my $linha = <ARGV> ) {
>   if ($linha =~ s/^>.+$/>contig$i/ ) {
>     $i++;
>   }
>   die "erro editando arquivo in-place: $!\n"
>     unless print $linha;
> }
> ---------->8-----------
> 
> Mas, se o efeito é o mesmo, pq usar continue? Simples: se amanhã vc
> quiser incrementar seu parser e pular linhas, sair do loop, etc, o que
> estiver dentro do bloco continue será executado mesmo após chamar
> "next". O efeito é o mesmo, e vc pode deixar sem o "continue" se te
> confundir (apenas lembre que ele existe, caso precise desse recurso no
> futuro).
> 
> Para mais informações: perldoc -f continue
> 
> 
> 
> Solução 4 (usando arquivos temporários)
> ================================
> 
> ----------8<-----------
> #!/usr/bin/env perl
> use strict;
> use warnings;
> use autodie;
> 
> my $nome_original = 'arquivo.txt';
> my $nome_tmp      = 'tmp.txt';
> 
> open my $orig_fh, '<', $nome_original;
> open my $tmp_fh,  '>', $nome_tmp;
> 
> my $i = 0;
> while ( my $linha = <$orig_fh> ) {
>   if ($linha =~ s/^>.+$/>contig$i/ ) {
>     $i++;
>   }
> }
> continue {
>     print $tmp_fh $linha;
> }
> 
> close $orig_fh;
> close $tmp_fh;
> rename $nome_tmp => $nome_original;
> ---------->8-----------
> 
> Essa abordagem com arquivo temporário usa menos memória do que a
> solução sem arquivos temporários mais abaixo. Também é mais segura de
> trabalhar e fácil de entender, e te dá a oportunidade de gravar um
> arquivo de backup - é só adicionar um rename($nome_original =>
> "outro_nome") antes do rename que está na última linha do exemplo.
> Outra vantagem é que vc pode gravar o nome dos arquivos de origem
> direto no programa ou em um arquivo de configurações, em vez de ser
> obrigado a passar o nome do arquivo como parâmetro, como nas soluções
> anteriores. Notas: certifique-se que os arquivos não estão sendo
> editados por mais ninguém durante o processo, de preferência com lock
> files. Outra: o rename() não funciona entre sistemas de arquivos,
> então crie o arquivo temporário de preferência no mesmo diretório do
> outro ou use File::Copy para uma solução realmente portátil.
> 
> 
> 
> Solução 5 (sem arquivos temporários)
> =============================
> 
> ----------8<-----------
> #!/usr/bin/env perl
> use strict;
> use warnings;
> use autodie;
> 
> open my $fh, '+<', 'arquivo.txt';
> 
> my @novas_linhas = ();
> my $i = 0;
> while ( my $linha = <$fh> ) {
>   if ($linha =~ s/^>.+$/>contig$i/ ) {
>     $i++;
>   }
> }
> continue {
>     push @novas_linhas => $linha;
> }
> 
> # volta ao inicio do arquivo,
> # sobrescreve tudo com as novas
> # e arranca fora (trunca) o que sobrar
> seek $fh, 0, 0;
> print $fh @novas_linhas;
> truncate $fh, tell($fh);
> close $fh;
> ---------->8-----------
> 
> Essa solução abre o arquivo em modo '+<' (update), o que te permite
> ler e escrever ao mesmo tempo no arquivo. Note que, se vc le e escreve
> AO MESMO TEMPO, o "stream de bytes" do arquivo muda o tempo todo, e
> você certamente vai se perder em relação ao ponto exato no arquivo em
> que seu handle está. Por isso, a solução é primeiro ler todo o arquivo
> em memória (ou ler somente as linhas que interessam, já com o conteúdo
> modificado, como fazemos acima), e só depois que processar todas as
> linhas, voltar ao início do arquivo e sobrescrever o conteúdo. De
> novo, faça lock do arquivo ou tenha certeza que ninguém vai editar o
> arquivo junto com seu programa.
> 
> Vale ressaltar que essa solução sem arquivo temporário só é
> recomendada se os arquivos forem pequenos e vc REALMENTE não puder
> usar arquivos temporários (por quê não poderia?), pois consome muito
> mais memória, é mais difícil de escrever, entender e manter, sem falar
> que não te dá a oportunidade de gravar uma cópia de segurança do
> arquivo original e pode confundir outros processos tentando ler o
> arquivo que você está editando.
> 
> Se, por outro lado, você puder GARANTIR que os tamanhos dos campos
> editáveis serão fixos (e substituidos pela mesma quantidade de bytes
> do mesmo tamanho), aí sim dá pra fazer algo bacana com o trio
> seek/read/print de forma eficiente e sem usar arquivos temporários.
> Mas isso normalmente só é verdade para arquivos binários.
> 
> Para mais informações: perldoc -f funcao (onde "funcao" seja uma das
> que foram usadas acima, tipo seek, tell e truncate).
> Para mais informações sobre lockfiles: perldoc -f flock
> 
> 
> 
> Bom, é isso. A solução 1 é a mais prática, mas não escala bem.
> Particularmente, prefiro a solução número 4, pelos motivos já citados.
> 
> Se essa foi realmente a sua pergunta, taí. Agora, se não foi, espero
> que pelo menos ajude alguém :)
> 
> Finalmente, mais uma dica: essas e muitas outras "receitas" podem ser
> encontradas no fantástico livro "Perl Cookbook" do Tom Christiansen e
> do Nathan Torkington. Foi um dos meus primeiros livros de Perl e um
> dos poucos que vira e mexe ainda consulto. Está todo muito bem
> dividido em grupos de problemas (string, arquivos, regex,...) e vc
> encontra rapidamente o que quer olhando o índice. Cada problema vem
> com a solução e uma discussão em cima do problema, de forma bastante
> didática.
> 
> 
> Versão Eletrônica (apenas Kindle):
> -----------------------------------------------
> 
> R$ 48,68 na amazon.com.br
> http://www.amazon.com.br/Perl-Cookbook-COOKBOOKS-ebook/dp/B0043GXMTS/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1354942271&sr=1-1
> 
> USD$ 22,79 na amazon.com
> http://www.amazon.com/Perl-Cookbook-COOKBOOKS-ebook/dp/B0043GXMTS/ref=sr_1_1?ie=UTF8&qid=1354942175&sr=8-1&keywords=perl+cookbook+kindle
> 
> 
> Versão Eletrônica (vários formatos pra escolher):
> -----------------------------------------------------------------
> 
> USD$ 19,99* na loja da O'Reilly
> http://shop.oreilly.com/product/9780596003135.do
> 
> *USD$ o preço real da versão eletrônica é 39,99. Como vc faz parte de
> um grupo de usuários filiado à O'Reilly, é só usar o código de
> desconto "DSUG" e ganhar 50% de desconto para ebooks (40% para livros
> impressos).
> 
> R$48,49 na Cultura
> http://www.livrariacultura.com.br/scripts/resenha/resenha.asp?nitem=17405530&sid=12225113814128111046650811
> 
> 
> Versão Impressa:
> ------------------------
> 
> - não encontrei na Saraiva
> 
> - na Cultura tem sob encomenda, à R$144,40 (+frete)
> 
> - na Estante Virtual só tem 1 exemplar, à R$90,00 (+frete)
> http://www.estantevirtual.com.br/arkanthum/Tom-Christiansen-e-Nathan-Torkington-Perl-Cookbook-72690537
> 
> 
> Independente da sua escolha, é um livro que recomendo vivamente para a
> cabeceira de qualquer programador Perl, especialmente para quem está
> começando. Me ajudou bastante e tenho certeza que vai ajudar você
> também. Acredite: vale *cada* centavo.
> 
> 
> Qq dúvida, como sempre, estamos aí!
> 
> []s
> 
> -b
> _______________________________________________
> Rio-pm mailing list
> Rio-pm em pm.org
> http://mail.pm.org/mailman/listinfo/rio-pm
 		 	   		  
-------------- Próxima Parte ----------
Um anexo em HTML foi limpo...
URL: <http://mail.pm.org/pipermail/rio-pm/attachments/20121208/0b68de60/attachment-0001.html>


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