我有一个标签分隔符。文本文件由许多行和列组成。我想更改前两列的内容,然后将修改后的文件写入新文件 在更改之前,每行的前两列看起来像这样:
COLUMN1:
dip:DIP-41935N|refseq:NP_056092|uniprotkb:Q96PU5
COLUMN2: dip:DIP-48957N|uniprotkb:P49281
我希望它们只包含每列末尾的id号,所以我希望它们如下:
COLUMN1: Q96PU5
COLUMN 2: P49281
我已在选项卡中拆分行以获取各列。然后拆分前两列以获取所需的ID号($ prot_id)。然后我尝试用ID代替第1列和第2列的内容。但是更改后的文件中的输出并不像我预期的那样。它看起来像这样:
COLUMN1:
Q96PU5|refseq:NP_056092|uniprotkb:Q96PU5
COLUMN 2:
P49281|uniprotkb:P49281
只是列的第一部分已被替换。我已经玩了好几个小时,无法弄清楚我做错了什么。任何帮助非常感谢。 我的代码如下:
#!/usr/bin/perl
use warnings;
use strict;
my $file = 'DIP.txt';
open(INFILE, $file) or die "Can't open file: $!\n";
open(my $outfile, '>', 'DIP_changed.txt');
my @lines = <INFILE>;
foreach $_ (@lines) {
my @columns = split('\t', $_);
my $col1 = $columns[0];
my $col2 = $columns[1];
my @split_col1 = split ('uniprotkb:', $col1);
my @split_col2 = split ('uniprotkb:', $col2);
my $prot_id1 = $split_col1[length(@split_col1)];
my $prot_id2 = $split_col2[length(@split_col2)];
print $prot_id1, "\n";
s/$col1/$prot_id1/;
s/$col2/$prot_id2/;
print {$outfile} $_;
}
exit;
答案 0 :(得分:2)
已经有了不错的答案,但我想向您展示一个更简单的解决方案。这个脚本,您可以这样使用:
$ script.pl DIP.txt > DIP_changed.txt
脚本本身就是:
while (<>) {
s/\S+uniprotkb:(\S+)/$1/;
s/\S+uniprotkb:(\S+)/$1/;
print;
}
它不需要比那更复杂。
答案 1 :(得分:1)
尝试这样的事情:
这是一个简洁的Perl习语 - 匹配像这样的正则表达式上的字符串
$columns[0]=~/:((\w|\d)*)$/;
(注意那里用括号定义了两个原子)并将匹配的结果(无论是第1,第2等原子)分配给数组 - 还是分配给一组标量变量。数组列表,如下所示:
($columns[0]) = $columns[0]=~/:((\w|\d)*)$/;
看,你是在正确的轨道,但你正在使它变得比它需要的更难:)
#!/usr/bin/perl
use warnings;
use strict;
my $file = 'DIP.txt';
open(INFILE, $file) or die "Can't open file: $!\n";
open(my $outfile, '>', 'DIP_changed.txt');
foreach my $line (<INFILE>) {
print "The input line is $line\n";
my @columns = split('\t', $line);
($columns[0]) = $columns[0]=~/:((\w|\d)*)$/;
($columns[1]) = $columns[1]=~/:((\w|\d)*)$/;
printf "The output line is %s\n", join ',', @columns;
printf $outfile join ',', @columns;
}
答案 2 :(得分:1)
ratsbane的回答非常好,但是你可能想知道工作时间为什么你得到了答案。原因是$ col1中有一个管道。这是正则表达式中的“OR”。因此,当您尝试替换正则表达式$ col1时,您正在执行查找并替换
dip:DIP-41935N|refseq:NP_056092|uniprotkb:Q96PU5
现在作为正则表达式,它匹配什么?它仅匹配
dip:DIP-41935N
所以 是被取代的东西!
希望有所帮助!
答案 3 :(得分:1)
可能没有什么理由在开头啜饮文件,而不是逐行处理。逐行处理将更好地扩展。考虑到这一点,我会这样做:
use warnings;
use strict;
my $file = 'DIP.txt';
open my $in_fh, '<', $file or die $!;
open my $out_fh, '>', 'new' . $file or die $!;
while ( <$in_fh> ) {
chomp;
next unless length $_; # Skip blank lines.
my ( @columns ) = split /\s+/, $_; # Split on whitespace (you may prefer \t).
foreach my $column ( @columns ) {
( $column ) = $column =~ m{([^:]+)$};
}
local $" = "\t";
print $out_fh "@columns\n";
}
首先,它在输入文件和输出文件中使用open的三个arg版本。这是一个很好的习惯。接下来,它使用词法文件句柄而不是旧的fileglob文件句柄。当Lexical超出范围时自动关闭,并且不会成为全局符号表的一部分。
接下来,脚本会读取文件并逐行处理,以避免啜饮。如果文件可能变大,或者您处于内存使用率非常高的环境中,这可能是有利的。除非你有充分的理由去啜饮,否则也可能养成不这样做的习惯。
然后我分裂了空白。您可以拆分选项卡。除非列中嵌入了空格,否则两种方式都有效。然后我遍历两列,匹配并捕获不是冒号的列末尾的每个内容。或另一种方式,即最后一次冒号之后的所有事情。我将结果捕获回$ column变量,该变量将@columns中的相应元素别名化。这样,当我完成时@columns只保存我的捕获。
最后,在处理了两列之后,我们对$“进行了本地化,为其分配了一个制表符。这样,当我们通过在引号中包装@columns来打印两列时,插值会自动在列之间再次添加制表符。如果你喜欢不同的角色,你现在知道在哪里改变它。
然后while循环移动到下一行。将跳过任何空白行。
请参阅perldoc open,perlretut,perlvar和perlop,以解释三个arg open和lexical文件句柄,regexp的解释,Perl的特殊变量,如$“,以及引用插值如何工作。
好问题!