我有制表符分隔的数据。我想使用perl处理该数据。我是perl的新手,无法弄清楚如何解决。
这是示例表:我的原始文件几乎是GB
gi|306963568|gb|GL429799.1|_1316857_1453052 13 1
gi|306963568|gb|GL429799.1|_1316857_1453052 14 1
gi|306963568|gb|GL429799.1|_1316857_1453052 15 1
gi|306963568|gb|GL429799.1|_1316857_1453052 16 1
gi|306963568|gb|GL429799.1|_1316857_1453052 17 1
gi|306963568|gb|GL429799.1|_1316857_1453052 360 1
gi|306963568|gb|GL429799.1|_1316857_1453052 361 1
gi|306963568|gb|GL429799.1|_1316857_1453052 362 1
gi|306963568|gb|GL429799.1|_1316857_1453052 363 1
gi|306963568|gb|GL429799.1|_1316857_1453052 364 1
gi|306963568|gb|GL429799.1|_1316857_1453052 365 1
gi|306963568|gb|GL429799.1|_1316857_1453052 366 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38640 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38641 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38642 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38643 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38644 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38645 1
我想把输出作为 名称,起始值,结束值,平均值
gi|306963568|gb|GL429799.1|_1316857_1453052 13 17 1
gi|306963568|gb|GL429799.1|_1316857_1453052 360 366 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38640 38645 1
如果有人可以分享他们的智慧,那将会很棒。
答案 0 :(得分:1)
一般模式是
use strict;
use warnings;
open my $fh, '<', 'myfile' or die $!;
while (<$fh>) {
chomp;
my @fields = split /\t/;
...
}
在循环中,字段可以$fields[0]
到$fields[2]
进行访问。
<强>更新强>
我更了解你的问题,我认为这个解决方案对你有用。 请注意,它假定输入数据已排序,如您在问题中所示。
它累计哈希%data
中的起始值和结束值,总计数和计数,并保留@names
中遇到的所有名称的列表,以便数据按顺序显示被读了。
程序期望输入文件名作为命令行上的参数。
您需要考虑平均值的格式,因为它是浮点值。目前它将显示十六个有效数字的值,您可能希望使用sprintf
来缩减它。
use strict;
use warnings;
my ($filename) = @ARGV;
open my $fh, '<', $filename or die qq{Unable to open "$filename": $!};
my @names;
my %data;
my $current_name = '';
my $last_index;
while (<$fh>) {
chomp;
my ($name, $index, $value) = split /\t/;
if ( $current_name ne $name or $index > $last_index + 1 ) {
push @names, $name unless $data{$name};
push @{ $data{$name} }, {
start => $index,
count => 0,
total => 0,
};
$current_name = $name;
}
my $entry = $data{$name}[-1];
$entry->{end} = $index;
$entry->{count} += 1;
$entry->{total} += $value;
$last_index = $index;
}
for my $name (@names) {
for my $entry (@{ $data{$name} }) {
my ($start, $end, $total, $count) = @{$entry}{qw/ start end total count /};
print join("\t", $name, $start, $end, $total / $count), "\n";
}
}
<强>输出强>
gi|306963568|gb|GL429799.1|_1316857_1453052 13 17 1
gi|306963568|gb|GL429799.1|_1316857_1453052 360 366 1
gi|306963580|gb|GL429787.1|_4276355_4500645 38640 38645 1
答案 1 :(得分:0)
这将为您的问题中的样本生成相同的输出:
#!/usr/bin/env perl -n
#
my ($name, $i, $value) = split(/\t/);
sub print_stats {
print join("\t", $prev_name, $start, $prev_i, $sum / ($prev_i - $start + 1)), "\n";
}
if ($prev_name eq $name && $i == $prev_i + 1) {
$sum += $value;
$prev_i = $i;
}
else {
if ($prev_name) {
&print_stats();
}
$start = $i;
$prev_name = $name;
$sum = $value;
$prev_i = $i;
}
END {
&print_stats();
}
将其用作:
./parser.pl < sample.txt
更新:回答评论中的问题:
./parser.pl < sample.txt > output.txt
$prev_name
和$prev_i
未初始化,因此它们最初为undef
(= NULL)答案 2 :(得分:-1)
你可以这样做......
open (FILE, 'data.txt');
while (<FILE>) {
chomp;
($name, $start_value, $end_value, $average) = split("\t");
print "Name: $name\n";
print "Start Value: $start_value\n";
print "End Value: $End_Value\n";
print "Average: %average
print "---------\n";
}
close (FILE);
exit;
那些看起来像GenBank文件......所以我不确定你在哪里获得开始,结束值,平均值。
答案 3 :(得分:-1)
以下是使用Text::CSV的示例:
use Text::CSV; # This will implicitly use Text::CSV_XS if it's installed
my $parser = Text::CSV->new( { sep_char => '|' } );
open my $fh, '<', 'myfile' or die $!;
while (my $row = $parser->getline($fh)) {
# $row references an array of field values from the line just read
}
此外,作为次要的细节,您的示例数据由管道字符分隔,而不是制表符,但这可能只是为了避免回答您问题的人员的复制/粘贴错误。如果实际数据以制表符分隔,请将sep_char
设置为"\t"
而不是'|'
。