循环遍历 perl 中的列的问题
Issue with looping through columns in perl
我编写的脚本有问题。我已将其分解以确定问题所在。
输入文件(制表符分隔):
FORMAT Sample1 Sample2 Sample3
GT:AD:DP:GQ:PL 0/1:17,6:23:85:85,0,370 0/0:51,6:57:17:0,17,1359 0/0:3,0:3:9:0,9,99
GT:AD:DP:GQ:PGT:PID:PL 0/0:3,0:3:0:.:.:0,0,38 0/0:1,0:1:3:.:.:0,3,33 0/1:1,2:3:26:0|1:13813_T_G:81,0,26
GT:AD:DP:GQ:PGT:PID:PL ./.:2,0:2:.:.:.:0,0,0 0/0:1,0:1:3:.:.:0,3,33 0/1:1,2:3:26:0|1:13813_T_G:81,0,26
GT:AD:DP:GQ:PL ./.:0,0:0:.:0,0,0 1/1:0,4:4:12:131,12,0 ./.:0,0:0:.:0,0,0
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:2,0:2:6:.:.:0,6,72 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PL 1/1:0,7:7:21:186,21,0 0/1:5,4:9:79:79,0,103 ./.:1,0:1:.:0,0,0
每行所需的输出(从每个样本的冒号前取前 3 个字符)并打印每行:
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL ./. 0/0 0/1
GT:AD:DP:GQ:PL ./. 1/1 ./.
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PL 1/1 0/1 ./.
我用来执行此步骤的代码没有按每行预期的那样生成正确的 0/0、0/1、0/2 代码。我认为这是我如何编写 for 循环的问题,但我不确定。
#!/usr/bin/perl
use strict;
my $inputfile1 = $ARGV[0];
open (FILE1, $inputfile1) or die "Uh oh.. unable to find file $inputfile1"; ##Opens input file
my @file1 = <FILE1>; #loads inputfile1 data into array
close FILE1;
my (@colsplit, @genotypes1, @genotypes2, @genotypes3, @joined);
foreach my $line(@file1) { ## process each line, splitting columns and move onto next line
@colsplit = split("\t", $line);
push (@joined, $colsplit[0]);
foreach my $lines(@colsplit) {
if ($colsplit[1] =~ m/(^0\/1)/ || $colsplit[1] =~ m/(^0\/0)/ || $colsplit[1]=~ m/(^1\/0)/ || $colsplit[1] =~ m/(^1\/1)/ || $colsplit[1] =~ m/(^.\/.)/) {
push (@genotypes1, );
}
if ($colsplit[2] =~ m/(^0\/1)/ || $colsplit[2] =~ m/(^0\/0)/ || $colsplit[2] =~ m/(^1\/0)/ || $colsplit[2] =~ m/(^1\/1)/ || $colsplit[2] =~ m/(^.\/.)/) {
push (@genotypes2, );
}
if ($colsplit[3] =~ m/(^0\/1)/ || $colsplit[3] =~ m/(^0\/0)/ || $colsplit[3] =~ m/(^1\/0)/ || $colsplit[3] =~ m/(^1\/1)/ || $colsplit[3] =~ m/(^.\/.)/) {
push (@genotypes3, );
}
}
}
my $i = 0;
foreach my $line(@joined) {
if ($line =~ m/GT/) {
print "$line\t$genotypes1[$i]\t$genotypes2[$i]\t$genotypes3[$i]\n";
$i++;
}}
我认为问题可能在于,一旦第一个 sample1 列匹配,它就会跳转到第二行,而不是遍历第二个 sample2 列。否则我看不出我是怎么搞砸的!快把我逼疯了!
我当前的输出是:
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PL ./. 0/0 0/1
这显然不是我想要的!
如有任何帮助,我们将不胜感激。
Ps。我是新手,所以放轻松。
问题似乎很清楚,要在每一列中保留 :
之前的数据(第一列除外)。但是后来我对尝试的代码感到有些困惑,这些代码不必要地经历了列的特定模式。
这里简单介绍一下所描述的内容
use warnings;
use strict;
use feature 'say';
my $header_line = <>; # drop the first line
while (<>) { # line by line from files given on cmdline, or STDIN
chomp;
my ($fmt_col, @cols) = split /\t/; # (but sample has spaces, not tabs)
s/(.*?):.*// for @cols; # keep up to (first) : in each field
say join "\t", $fmt_col, @cols; # print fields joined by tabs
}
<>
从命令行中给定的所有文件中读取所有行,或 STDIN
;所以当 运行 这个程序时,在命令行上提交一个文件名来处理。
请注意,发布的示例没有制表符,而是空格;所以上面的代码如果复制粘贴就会失败。要么将空格更改为制表符以进行测试,要么将 split /\t/;
更改为 split;
(以便使用其默认拆分,即任意数量的任意空格)。
除第一个字段之外的所有字段都已更改,以便仅保留第一个 :
之前的字符。
这是使用在 foreach
循环(“topicalizer”)中处理的每个项目都别名为当前处理的元素这一事实来完成的。因此,当正则表达式 s///
更改它时, @cols
的相应元素也会更改。如果这看起来太难吃,请一定要慢慢地把它写出来。
如果确实需要做其他事情,请说明。
我相信我已经解决了这个问题。我删除了 foreach my $lines(@colsplit) {
,现在可以使用了!代码如下:
#!/usr/bin/perl
use strict;
my $inputfile1 = $ARGV[0];
open (FILE1, $inputfile1) or die "Uh oh.. unable to find file $inputfile1"; ##Opens input file
my @file1 = <FILE1>; #loads inputfile1 data into array
close FILE1;
my (@colsplit, @genotypes1, @genotypes2, @genotypes3, @joined);
foreach my $line(@file1) { ## process each line, splitting columns and move onto next line
@colsplit = split("\t", $line);
push (@joined, $colsplit[0]);
if ($colsplit[1] =~ m/(^0\/1)/ || $colsplit[1] =~ m/(^0\/0)/ || $colsplit[1]=~ m/(^1\/0)/ || $colsplit[1] =~ m/(^1\/1)/ || $colsplit[1] =~ m/(^.\/.)/) {
push (@genotypes1, );
}
if ($colsplit[2] =~ m/(^0\/1)/ || $colsplit[2] =~ m/(^0\/0)/ || $colsplit[2] =~ m/(^1\/0)/ || $colsplit[2] =~ m/(^1\/1)/ || $colsplit[2] =~ m/(^.\/.)/) {
push (@genotypes2, );
}
if ($colsplit[3] =~ m/(^0\/1)/ || $colsplit[3] =~ m/(^0\/0)/ || $colsplit[3] =~ m/(^1\/0)/ || $colsplit[3] =~ m/(^1\/1)/ || $colsplit[3] =~ m/(^.\/.)/) {
push (@genotypes3, );
}
}
my $i = 0;
foreach my $line(@joined) {
if ($line =~ m/GT/) {
print "$line\t$genotypes1[$i]\t$genotypes2[$i]\t$genotypes3[$i]\n";
$i++;
}}
特别感谢@zdim 向我展示了一个更优雅的解决方案。
E
一种可能的方法是使用正则表达式匹配的continuation modifier (c
)。它会导致匹配操作从最后一个找到匹配项的地方开始。这样,一行的每个字段都可以处理。
#!/usr/bin/perl
use strict;
use warnings;
my $fh;
$ARGV[0] && open($fh, $ARGV[0]) || die();
# discard first line;
<$fh>;
foreach my $line (<$fh>) {
chomp($line);
# capture every non tab character from the beginning of the line;
# globally match the pattern repeatedly in the string (g modifier)
# keep the current position during repeated matching (c modifier);
$line =~ m/^([^\t]*)/gc;
print("");
# capture every non colon character after a tab character;
# globally match the pattern repeatedly in the string (g modifier);
# keep the current position during repeated matching (c modifier);
while ($line =~ m/\t([^:]*)/gc) {
print("\t");
}
print("\n");
}
我编写的脚本有问题。我已将其分解以确定问题所在。
输入文件(制表符分隔):
FORMAT Sample1 Sample2 Sample3
GT:AD:DP:GQ:PL 0/1:17,6:23:85:85,0,370 0/0:51,6:57:17:0,17,1359 0/0:3,0:3:9:0,9,99
GT:AD:DP:GQ:PGT:PID:PL 0/0:3,0:3:0:.:.:0,0,38 0/0:1,0:1:3:.:.:0,3,33 0/1:1,2:3:26:0|1:13813_T_G:81,0,26
GT:AD:DP:GQ:PGT:PID:PL ./.:2,0:2:.:.:.:0,0,0 0/0:1,0:1:3:.:.:0,3,33 0/1:1,2:3:26:0|1:13813_T_G:81,0,26
GT:AD:DP:GQ:PL ./.:0,0:0:.:0,0,0 1/1:0,4:4:12:131,12,0 ./.:0,0:0:.:0,0,0
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:3,0:3:9:.:.:0,9,98 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PGT:PID:PL 1/1:0,2:2:6:1|1:14590_G_A:90,6,0 0/0:2,0:2:6:.:.:0,6,72 0/0:1,0:1:3:.:.:0,3,30
GT:AD:DP:GQ:PL 1/1:0,7:7:21:186,21,0 0/1:5,4:9:79:79,0,103 ./.:1,0:1:.:0,0,0
每行所需的输出(从每个样本的冒号前取前 3 个字符)并打印每行:
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL ./. 0/0 0/1
GT:AD:DP:GQ:PL ./. 1/1 ./.
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 1/1 0/0 0/0
GT:AD:DP:GQ:PL 1/1 0/1 ./.
我用来执行此步骤的代码没有按每行预期的那样生成正确的 0/0、0/1、0/2 代码。我认为这是我如何编写 for 循环的问题,但我不确定。
#!/usr/bin/perl
use strict;
my $inputfile1 = $ARGV[0];
open (FILE1, $inputfile1) or die "Uh oh.. unable to find file $inputfile1"; ##Opens input file
my @file1 = <FILE1>; #loads inputfile1 data into array
close FILE1;
my (@colsplit, @genotypes1, @genotypes2, @genotypes3, @joined);
foreach my $line(@file1) { ## process each line, splitting columns and move onto next line
@colsplit = split("\t", $line);
push (@joined, $colsplit[0]);
foreach my $lines(@colsplit) {
if ($colsplit[1] =~ m/(^0\/1)/ || $colsplit[1] =~ m/(^0\/0)/ || $colsplit[1]=~ m/(^1\/0)/ || $colsplit[1] =~ m/(^1\/1)/ || $colsplit[1] =~ m/(^.\/.)/) {
push (@genotypes1, );
}
if ($colsplit[2] =~ m/(^0\/1)/ || $colsplit[2] =~ m/(^0\/0)/ || $colsplit[2] =~ m/(^1\/0)/ || $colsplit[2] =~ m/(^1\/1)/ || $colsplit[2] =~ m/(^.\/.)/) {
push (@genotypes2, );
}
if ($colsplit[3] =~ m/(^0\/1)/ || $colsplit[3] =~ m/(^0\/0)/ || $colsplit[3] =~ m/(^1\/0)/ || $colsplit[3] =~ m/(^1\/1)/ || $colsplit[3] =~ m/(^.\/.)/) {
push (@genotypes3, );
}
}
}
my $i = 0;
foreach my $line(@joined) {
if ($line =~ m/GT/) {
print "$line\t$genotypes1[$i]\t$genotypes2[$i]\t$genotypes3[$i]\n";
$i++;
}}
我认为问题可能在于,一旦第一个 sample1 列匹配,它就会跳转到第二行,而不是遍历第二个 sample2 列。否则我看不出我是怎么搞砸的!快把我逼疯了!
我当前的输出是:
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PL 0/1 0/0 0/0
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PGT:PID:PL 0/0 0/0 0/1
GT:AD:DP:GQ:PL ./. 0/0 0/1
这显然不是我想要的!
如有任何帮助,我们将不胜感激。
Ps。我是新手,所以放轻松。
问题似乎很清楚,要在每一列中保留 :
之前的数据(第一列除外)。但是后来我对尝试的代码感到有些困惑,这些代码不必要地经历了列的特定模式。
这里简单介绍一下所描述的内容
use warnings;
use strict;
use feature 'say';
my $header_line = <>; # drop the first line
while (<>) { # line by line from files given on cmdline, or STDIN
chomp;
my ($fmt_col, @cols) = split /\t/; # (but sample has spaces, not tabs)
s/(.*?):.*// for @cols; # keep up to (first) : in each field
say join "\t", $fmt_col, @cols; # print fields joined by tabs
}
<>
从命令行中给定的所有文件中读取所有行,或 STDIN
;所以当 运行 这个程序时,在命令行上提交一个文件名来处理。
请注意,发布的示例没有制表符,而是空格;所以上面的代码如果复制粘贴就会失败。要么将空格更改为制表符以进行测试,要么将 split /\t/;
更改为 split;
(以便使用其默认拆分,即任意数量的任意空格)。
除第一个字段之外的所有字段都已更改,以便仅保留第一个 :
之前的字符。
这是使用在 foreach
循环(“topicalizer”)中处理的每个项目都别名为当前处理的元素这一事实来完成的。因此,当正则表达式 s///
更改它时, @cols
的相应元素也会更改。如果这看起来太难吃,请一定要慢慢地把它写出来。
如果确实需要做其他事情,请说明。
我相信我已经解决了这个问题。我删除了 foreach my $lines(@colsplit) {
,现在可以使用了!代码如下:
#!/usr/bin/perl
use strict;
my $inputfile1 = $ARGV[0];
open (FILE1, $inputfile1) or die "Uh oh.. unable to find file $inputfile1"; ##Opens input file
my @file1 = <FILE1>; #loads inputfile1 data into array
close FILE1;
my (@colsplit, @genotypes1, @genotypes2, @genotypes3, @joined);
foreach my $line(@file1) { ## process each line, splitting columns and move onto next line
@colsplit = split("\t", $line);
push (@joined, $colsplit[0]);
if ($colsplit[1] =~ m/(^0\/1)/ || $colsplit[1] =~ m/(^0\/0)/ || $colsplit[1]=~ m/(^1\/0)/ || $colsplit[1] =~ m/(^1\/1)/ || $colsplit[1] =~ m/(^.\/.)/) {
push (@genotypes1, );
}
if ($colsplit[2] =~ m/(^0\/1)/ || $colsplit[2] =~ m/(^0\/0)/ || $colsplit[2] =~ m/(^1\/0)/ || $colsplit[2] =~ m/(^1\/1)/ || $colsplit[2] =~ m/(^.\/.)/) {
push (@genotypes2, );
}
if ($colsplit[3] =~ m/(^0\/1)/ || $colsplit[3] =~ m/(^0\/0)/ || $colsplit[3] =~ m/(^1\/0)/ || $colsplit[3] =~ m/(^1\/1)/ || $colsplit[3] =~ m/(^.\/.)/) {
push (@genotypes3, );
}
}
my $i = 0;
foreach my $line(@joined) {
if ($line =~ m/GT/) {
print "$line\t$genotypes1[$i]\t$genotypes2[$i]\t$genotypes3[$i]\n";
$i++;
}}
特别感谢@zdim 向我展示了一个更优雅的解决方案。 E
一种可能的方法是使用正则表达式匹配的continuation modifier (c
)。它会导致匹配操作从最后一个找到匹配项的地方开始。这样,一行的每个字段都可以处理。
#!/usr/bin/perl
use strict;
use warnings;
my $fh;
$ARGV[0] && open($fh, $ARGV[0]) || die();
# discard first line;
<$fh>;
foreach my $line (<$fh>) {
chomp($line);
# capture every non tab character from the beginning of the line;
# globally match the pattern repeatedly in the string (g modifier)
# keep the current position during repeated matching (c modifier);
$line =~ m/^([^\t]*)/gc;
print("");
# capture every non colon character after a tab character;
# globally match the pattern repeatedly in the string (g modifier);
# keep the current position during repeated matching (c modifier);
while ($line =~ m/\t([^:]*)/gc) {
print("\t");
}
print("\n");
}