Como posso dividir um arquivo de texto em vários arquivos de texto usando o Perl?

4

Eu tenho um arquivo ABC_TabDelim.txt que contém o seguinte:

00:00:00:00 00:00:05:00 01SC_001.jpg
00:00:14:29 00:00:19:29 01SC_002.jpg
00:01:07:20 00:01:12:20 01SC_003.jpg
00:00:00:00 00:00:03:25 02MI_001.jpg
00:00:03:25 00:00:08:25 02MI_002.jpg
00:00:35:27 00:00:40:27 02MI_003.jpg
00:00:00:00 00:00:05:00 03Bi_001.jpg
00:00:05:19 00:00:10:19 03Bi_002.jpg
00:01:11:17 00:01:16:17 03Bi_003.jpg
00:00:00:00 00:00:05:00 04CG_001.jpg
00:00:11:03 00:00:16:03 04CG_002.jpg
00:01:12:25 00:01:17:25 04CG_003.jpg

Gostaria de dividir isso em vários arquivos para cada instância de 00: 00: 00: 00, exibindo-a como ABC01_TabDelim.txt, ABC02_TabDelim.txt, ABC03_TabDelim.txt, etc.

Portanto, 00: 00: 00: 00 indicaria que um novo arquivo deve começar. Existe alguma maneira de conseguir isso com um script Perl?

    
por Jon Barnett 13.02.2013 / 17:06

5 respostas

3

Isso funcionará para o formato dado. Isso pressupõe que o arquivo sempre comece com 00: 00: 00: 00.

#!/usr/bin/env perl

use strict;
use warnings;

open(my $infh, '<', 'ABC_TabDelim.txt') or die $!;

my $outfh;
my $filecount = 0;
while ( my $line = <$infh> ) {
    if ( $line =~ /^00:00:00:00/ ) {
        close($outfh) if $outfh;
        open($outfh, '>', sprintf('ABC%02d_TabDelim.txt', ++$filecount)) or die $!;        
    }
    print {$outfh} $line or die "Failed to write to file: $!";
}

close($outfh);
close($infh);
    
por 13.02.2013 / 17:15
3

Aqui vai você. Nenhuma verificação de erros, executada como, por exemplo, perl split file-to-munge

Atualização: Limpeza de script sugerida por goldilocks

#!/usr/bin/perl

$n = 1;
while(<>) {
    if(/^00:00:00:00/) {
        close($out) if(n != 1);
        $fn = sprintf("ABC%02d_TabDelim.txt", $n++);
        open($out, ">", "$fn");
    }
    print OUT;
}
    
por 13.02.2013 / 17:20
2

Se for esperado que a saída para essa entrada de amostra seja de 4 arquivos, cada um com 3 linhas, sendo que cada linha 1 é uma começando com “00: 00: 00: 00” e as outras 2 linhas as seguintes, isso:

perl -ne 'if(/^[0:]{11}/){close F if$f;open F,sprintf(">ABC%02d_TabDelim.txt",++$f)}print F' ABC_TabDelim.txt
    
por 13.02.2013 / 17:15
2

Você não precisa do Perl para isso: você pode usar o utilitário de shell padrão csplit . Há uma limitação: o nome dos arquivos de saída tem que ser xxx00, xxx01, etc., então você precisará adicionar o sufixo desejado depois.

csplit -s -f ABC ABC_TabDelim.txt '/^00:00:00:00/' '{999999999}'
rm ABC00  # empty file (containing everything up to the first 00:00:00:00)
for x in ABC[0-9][0-9]; do mv "$x" "${x}_TabDelim.txt"; done

O argumento {*} para repetir o delimitador anterior tantas vezes quanto possível é uma extensão GNU. POSIX csplit requer um primeiro passe com grep.

    
por 14.02.2013 / 02:19
1

Você tem uma solução para o perl, aqui está uma maneira de fazer isso com o awk:

awk '/00:00:00:00/ { out = sprintf("ABC%02d_TabDelimit.txt", ++i) } { print > out }' ABC_TabDelim.txt

Se você tiver que dividir em muitos arquivos que você gostaria de fechar cada arquivo, preencha a função sprintf com if(out) close(out) :

awk '/00:00:00:00/ { if(out) close(out); out = sprintf("ABC%02d_TabDelimit.txt", ++i) } { print > out }' ABC_TabDelim.txt
    
por 14.02.2013 / 17:01