Lendo seções de um arquivo em Perl
Pergunta
Eu estou tentando ler valores de um arquivo de entrada em Perl. olhares de arquivo de entrada como:
1-sampledata1 This is a sample test
and data for this continues
2-sampledata2 This is sample test 2
Data for this also is on second line
Eu quero ler os dados acima para que os dados para 1-sampledata1
vai para @array1
e dados para 2-sampledata2
vai em @array2
e assim por diante.
I terá cerca de 50 seções como este. como 50-sampledata50
.
Editar : Os nomes não será sempre X-sampledataX. Eu só fiz isso por exemplo. Então nomes não pode estar em um loop. Eu acho que eu vou ter que digitá-los manualmente
Eu até agora tem o seguinte (que funciona). Mas eu estou procurando uma maneira mais eficiente de fazer isso ..
foreach my $line(@body){
if ($line=~ /^1-sampledata1\s/){
$line=~ s/1-ENST0000//g;
$line=~ s/\s+//g;
push (@array1, $line);
#using splitarray because i want to store data as one character each
#for ex: i wana store 'This' as T H I S in different elements of array
@splitarray1= split ('',$line);
last if ($line=~ /2-sampledata2/);
}
}
foreach my $line(@body){
if ($line=~ /^2-sampledata2\s/){
$line=~ s/2-ENSBTAP0//g;
$line=~ s/\s+//g;
@splitarray2= split ('',$line);
last if ($line=~ /3-sampledata3/);
}
}
Como você pode ver eu tenho matrizes diferentes para cada seção e diferente para loops para cada seção. Se eu ir com abordagem que, até agora, então eu vou acabar com 50 loops e 50 matrizes.
Existe outra maneira melhor de fazer isso? No final, eu quero acabar com 50 matrizes, mas não quero escrever 50 para loops. E desde que eu será loop através das 50 matrizes mais tarde no programa, talvez armazená-los em uma matriz? Eu sou novo para Perl pelo que a sua esmagadora meio ...
Solução
A primeira coisa a notar é que você está tentando usar nomes de variáveis ??com sufixos inteiros: Não. Usar uma matriz sempre que você encontrar o seu próprio querendo fazer isso. Em segundo lugar, você só precisa ler para passar por cima do conteúdo do arquivo de uma vez, e não várias vezes. Em terceiro lugar, geralmente há nenhuma boa razão em Perl para tratar uma string como um array de caracteres.
Update: Esta versão do usa código existência de espaços à esquerda para decidir o que fazer. Estou deixando a versão anterior se bem para referência.
#!/usr/bin/perl
use strict;
use warnings;
my @data;
while ( my $line = <DATA> ) {
chomp $line;
if ( $line =~ s/^ +/ / ) {
push @{ $data[-1] }, split //, $line;
}
else {
push @data, [ split //, $line ];
}
}
use Data::Dumper;
print Dumper \@data;
__DATA__
1-sampledata1 This is a sample test
and data for this continues
2-sampledata2 This is sample test 2
Data for this also is on second line
Versão anterior:
#!/usr/bin/perl
use strict;
use warnings;
my @data;
while ( my $line = <DATA> ) {
chomp $line;
$line =~ s/\s+/ /g;
if ( $line =~ /^[0-9]+-/ ) {
push @data, [ split //, $line ];
}
else {
push @{ $data[-1] }, split //, $line;
}
}
use Data::Dumper;
print Dumper \@data;
__DATA__
1-sampledata1 This is a sample test
and data for this continues
2-sampledata2 This is sample test 2
Data for this also is on second line
Outras dicas
#! /usr/bin/env perl
use strict;
use warnings;
my %data;
{
my( $key, $rest );
while( my $line = <> ){
unless( ($rest) = $line =~ /^ \s+(.*)/x ){
($key, $rest) = $line =~ /^(.*?)\s+(.*)/;
}
push @{ $data{$key} }, $rest;
}
}
O código abaixo é muito semelhante ao @ Brad Gilbert 's e @Sinan Unur ' As soluções:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my (%arrays, $label);
while (my $line = <DATA>)
{
($label, $line) = ($1, $2) if $line =~ /^(\S+)(.*)/; # new data block
$line =~ s/^\s+//; # strip whitespaces from the begining
# append data for corresponding label
push @{$arrays{$label}}, split('', $line) if defined $label;
}
print $arrays{'1-sampledata1'}[2], "\n"; # 'i'
print join '-', @{$arrays{'2-sampledata2'}}; # 'T-h-i-s- -i-s- -s-a-m-p-l
print Dumper \%arrays;
__DATA__
1-sampledata1 This is a sample test
and data for this continues
2-sampledata2 This is sample test 2
Data for this also is on second line
saída
i
T-h-i-s- -i-s- -s-a-m-p-l-e- -t-e-s-t- -2-D-a-t-a- -f-o-r- -t-h-i-s- -a-l-s-o- -i-s- -o-n- -s-e-c-o-n-d- -l-i-n-e-
$VAR1 = {
'2-sampledata2' => [
'T',
'h',
'i',
's',
' ',
'i',
's',
' ',
's',
'a',
'm',
'p',
'l',
'e',
' ',
't',
'e',
's',
't',
' ',
'2',
'D',
'a',
't',
'a',
' ',
'f',
'o',
'r',
' ',
't',
'h',
'i',
's',
' ',
'a',
'l',
's',
'o',
' ',
'i',
's',
' ',
'o',
'n',
' ',
's',
'e',
'c',
'o',
'n',
'd',
' ',
'l',
'i',
'n',
'e',
'
'
],
'1-sampledata1' => [
'T',
'h',
'i',
's',
' ',
'i',
's',
' ',
'a',
' ',
's',
'a',
'm',
'p',
'l',
'e',
' ',
't',
'e',
's',
't',
'a',
'n',
'd',
' ',
'd',
'a',
't',
'a',
' ',
'f',
'o',
'r',
' ',
't',
'h',
'i',
's',
' ',
'c',
'o',
'n',
't',
'i',
'n',
'u',
'e',
's',
'
'
]
};
Você deve, em vez disso, usar um mapa hash para arrays.
Use este padrão regex para obter o índice:
/^(\d+)-sampledata(\d+)/
E então, com my %arrays
, fazer:
push($arrays{$index}), $line;
Você pode acessar as matrizes com $arrays{$index}
.