我想创建包含文件1和文件2的值的输出文件。
文件1中的行:
chr1袖扣外显子708356 708487 1000 - 。
gene_id" CUFF.3&#34 ;; transcript_id" CUFF.3.1&#34 ;; exon_number" 5&#34 ;; FPKM " 3.1300591420&#34 ;; frac" 1.000000&#34 ;; conf_lo" 2.502470&#34 ;; conf_hi " 3.757648&#34 ;; cov" 7.589085&#34 ;; chr1Cufflinks外显子708356 708487 - 。 gene_id" XLOC_001284&#34 ;; transcript_id " TCONS_00007667&#34 ;; exon_number" 7&#34 ;; gene_name" LOC100288069&#34 ;; OID " CUFF.15.2&#34 ;; nearest_ref" NR_033908&#34 ;; class_code" j&#34 ;; tss_id " TSS2981&#34 ;;
文件2中的一行:
CUFF.48557
CHR4:160253850-160259462:160259621-160260265:160260507-160262715
此文件的第二列是唯一ID(uniq_id)。
我想以下列格式获取输出文件: transcript_id(CUFF_id)uniq_id gene_id(XLOC_ID)FPKM
我的脚本从第一个文件中获取XLOC_ID和FPKM值,并将它们与第二个文件中的两列一起打印出来。
record 1 --> 40 min --> record 2 --> 50 min --> record 3
我在文件外部初始化了哈希值,但是每个CUFF值都出现以下错误:
CUFF.24093
chr17:3533641-3539345:3527526-3533498:3526786-3527341:3524707-3526632在连接(。)中使用未初始化的值或在ex_1.pl中使用字符串 第55行,第9343行。
在连接(。)中使用未初始化的值或在ex_1.pl中使用字符串 第55行,第9343行。
如何解决此问题?
谢谢!
答案 0 :(得分:1)
我认为警告消息是因为$id
键,(CUFF.24093
),您上传第二个文件的9343
并未包含在您创建的哈希中在第一个文件中。
第二个文件中的ID是否可能不包含在第一个文件中?这似乎就是这种情况。
如果是这样,并且您只想跳过此未知ID,则可以在程序中添加一行,如:
my $id = $array[0];
my $uniq = $array[1];
next unless exists $fpkm_hash{$id}; # add this line
print $id . "\t" . $uniq . "\t" . $xloc_hash{$id} . "\t" . $fpkm_hash{$id} . "\n";
这将绕过以下print
语句并返回while
循环的顶部,并在下一行中读取并继续处理。
这取决于您遇到未知ID时要采取的操作。
更新:我想我可能会对您的代码进行一些观察/改进。
my $v_merge_gtf = shift @ARGV or die $!;
my $unique_gtf = shift @ARGV or die $!;
错误变量$!
在这里没有用处(这是我最近才发现的事实,即使在使用Perl 14年之后)。 $!仅设置为系统调用(您涉及操作系统)。最常见的是open并关闭文件,opendir和closedir用于目录。如果在打开/关闭文件或目录时发生错误,$!
将包含错误消息。 (请参阅我在附带的代码中处理此问题的方法 - 如果$usage
没有成功,我会创建一条消息,shift
。
我没有使用2个哈希来存储信息,而是使用了1个哈希%data
。优点是它将使用更少的内存,(因为它只存储1组密钥而不是2组),但是,如果你愿意,你可以使用2。
我使用推荐的3个参数(filehandle, mode, filename
)表单来打开文件。您使用的2参数方法已过时且安全性较低(原因我在此处未详细说明)。另外,我使用的词法文件句柄my $mrg
和my $unique
是创建文件句柄的新方法(而不是使用FILE
进行2次打开)。
您可以直接在{while循环中$line
分配while (my $line = <FILE>)
,而不是像$line
那样。在我的示例程序中,我没有分配给$_
,而是依赖于默认变量next unless /\S/; my @array = split /\t/;
。 (它简化了以下两个语句chomp
)。我没有chomp
第一个文件,因为你只是在字符串中解析而不是使用字符串末尾的任何内容。while
是必需的第二个my $uniq = ...
循环,因为第二个变量chomp
如果没有被if ($line =~ /[a-z]/)
移除,则会在其末尾有换行符。
我不知道这句话的意思,next unless /\S/;
。我假设您要检查空行并且只处理具有非空间数据的行。这就是我写my $id = $array[8];
的原因。 (说要跳过以下语句并进入while循环的顶部并阅读下一条记录)。
您的第一个while循环有效,因为输入文件中没有错误。如果有错误,你编写代码的方式可能就是一个问题。
如果以下$id
语句为false,则if
语句会为$fpkm
提供一个错误使用的值。 (对于您要捕获的其他2个变量,$xloc
和die
)也是如此。你可以在我的代码示例中看到我是如何处理这个的。
在我的代码中,如果匹配没有成功,我就死了,您可能不想match or next
而是说$array[8] =~ /gene_id "(CUFF\S+)";/
来尝试下一行数据。这取决于您希望如何处理失败的匹配。
在这一行";
中,请注意我将or die "Could not find ID in $v_merge_gtf (line# $.)";
放在捕获的数据之后,因此无需将其从捕获的数据中删除(就像您在替换中所做的那样)
嗯,我知道这是对您的代码的长篇评论,但我希望您能对我推荐更改的原因有所了解。
$.
#!/usr/bin/perl
use warnings;
use strict;
my $usage = "USAGE: perl $0 merge_gtf_file unique_gtf_file\n";
my $v_merge_gtf = shift @ARGV or die $usage;
my $unique_gtf = shift @ARGV or die $usage;
my %data;
open my $mrg, '<', $v_merge_gtf or die $!;
while (<$mrg>) {
next unless /\S/;
my @array = split /\t/;
if ($array[2] eq 'exon') {
$array[8] =~ /gene_id "(CUFF\S+)";/
or die "Could not find ID in $v_merge_gtf (line# $.)";
my $id = $1;
$array[8] =~ /FPKM "(\S+)";/
or die "Could not find FPKM in $v_merge_gtf (line# $.)";
my $fpkm = $1;
$array[17] =~ /gene_id "(XLOC\S+)";/
or die "Could not find XLOC in $v_merge_gtf (line# $.)";
my $xloc = $1;
$data{$id}{fpkm} = $fpkm;
$data{$id}{xloc} = $xloc;
}
}
close $mrg or die $!;
open my $unique, '<', $unique_gtf or die $!;
while (<$unique>) {
next unless /\S/;
chomp;
my ($id, $uniq) = split /\t/;
print join("\t", $id, $uniq, $data{$id}{fpkm}, $data{$id}{xloc}), "\n";
}
close $unique or die $!;
是正在读取的文件的行号。
{{1}}