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: [email protected] > To: [email protected] > 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 > [email protected] > http://mail.pm.org/mailman/listinfo/rio-pm
_______________________________________________ Rio-pm mailing list [email protected] http://mail.pm.org/mailman/listinfo/rio-pm
