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