如何使用tr ///运算符中的变量计算模式数?

时间:2012-05-01 16:30:40

标签: perl variables tr

我想计算核苷酸的出现次数(字符串中的字母'A,T,G,C')。我试图使用tr///运算符,但每次在下面的代码中都返回零。

只有在tr///运算符中使用变量时才会发生这种情况。如果我单独输入单个字母,它就可以工作。我想知道我们是否可以在tr///运算符中使用变量进行模式匹配(和计数)。如果可以,有人告诉我如何修改我的代码。

后来我计划计算密码子的数量(~64)。因此麻烦。感谢你的时间。谢谢!

#!/usr/bin/perl

use strict;
use warnings;

my $orf = "ATGCTAGCTAGCATAGAGCTAGCTA";
my @atgc = qw(A T G C);
my %hash = ();

foreach my $nt(@atgc) {
  $hash{$nt} = ($orf =~ tr/$nt//);
}

6 个答案:

答案 0 :(得分:4)

$”中没有“n”,“t”或“ATGCTAGCTAGCATAGAGCTAGCTA”的实例,因此tr正确返回零。

如果要构建tr///运算符,则需要解析并编译它。

my %counts;
for my $nt (@atgc) {
   $counts{$nt} = eval "\$orf =~ tr/\Q$nt\E//";
}

但我不会使用tr///

my %atgc = map { $_ => 1 } @atgc;
my %counts;
++$counts{$nt} for grep $atgc{$_}, split //, $orf;

答案 1 :(得分:4)

不幸的是,Perl不会将变量插入到tr///的搜索列表中。您将不得不使用正则表达式:

use strict;
use warnings;

my $orf = "ATGCTAGCTAGCATAGAGCTAGCTA";
my @atgc = qw(A T G C);
my %count;

$count{$1}++ while $orf =~ /([@atgc])/g;

printf "%s => %d\n", $_, $count{$_} for @atgc;

<强>输出

A => 8
T => 6
G => 6
C => 5

<强>当心

这不是 - 因为它可能会出现 - 一个匹配任何一个字符串数组的通用解决方案。正在发生的事情是将@atcg插入到正则表达式中,就像它在双引号字符串中一​​样。这意味着Perl将使用$"内置变量(默认设置为单个空格)将其转换为等效于join $", @atgc的字符串。

所以代码实际上就像

$count{$1}++ while $orf =~ /([A T G C])/g;
如果@atgc包含^]或{{1}等正则表达式字符类中的特殊内容,

将匹配空格和字母,并且可能会完全中断}。

不必要地计算空间应该不是问题,但如果您的列表可能包含符号,那么这不是您应该使用的解决方案。

每个ASCII字符的计数可以安全地写为

-

可以简单地忽略$count{$1}++ while $orf =~ /(.)/sg; 哈希中不需要的信息。

答案 2 :(得分:3)

$hash{$nt} = eval "\$orf =~ tr/\Q$nt\E//"

应该做的工作。也许这不是最有效的解决方案。

答案 3 :(得分:1)

您可以使用s///g

#!/usr/bin/env perl

use strict; use warnings;

my $orf = "ATGCTAGCTAGCATAGAGCTAGCTA";
my @atgc = qw(A T G C);

my %hash = map {$_ => $orf =~ s/$_/$_/g } @atgc;

输出:

---
A: 8
C: 5
G: 6
T: 6

如果源字符串非常长,您可以将其视为保留一段时间的内容并一次读取一个字节,假设字符保证为ASCII。

#!/usr/bin/env perl

use strict; use warnings;

my $orf = "ATGCTAGCTAGCATAGAGCTAGCTA";
my %atgc = map { $_ => undef } qw(A T G C);

use YAML;
print Dump count(\$orf, \%atgc);

sub count {
    my $src_ref = shift;
    my $lookup = shift;

    my %count;

    open my $src, '<', $src_ref or die $!;
    {
        local $/ = \1;
        exists $lookup->{$_} and $count{ $_ } += 1 while <$src>;
    }
    close $src;

    return \%count;
}

答案 4 :(得分:1)

你不需要正则表达式等来做这个,你只需要走一个字符串:

my $orf = "ATGCTAGCTAGCATAGAGCTAGCTA";
my %nt;

$nt{$_}++ foreach (split('', $orf));

答案 5 :(得分:1)

制作模式编译器。

sub make_counter {
  my @sequences = @_;

  my $pattern = "(?:" . join("|", map quotemeta, @sequences) . ")";

  my $compiled = eval q<
    sub {
      local($_) = @_;
      my $n = () = /$pattern/g;
    }
  >;

  if (defined $compiled) {
    return $compiled;
  }
  else {
    die "$0: internal: counter compilation failed:\n$@\n";
  }
}

使用quotemeta,我们强制序列中的所有字符仅匹配自己,没有特殊含义。 Section 4 of the Perl FAQ描述了用于计算匹配的时髦位:

  

另一个版本在列表上下文中使用全局匹配,然后将结果分配给标量,生成匹配数的计数。

$count = () = $string =~ /-\d+/g;

请注意,它可以容忍您序列中的垃圾。例如,用

计算核苷酸
my @nucleotides = qw/ G A T C /;

my $numnuc = make_counter @nucleotides;
print $numnuc->("xGxAxTxxxxTyA1C2A"), "\n";

输出:

7

计算密码子
my @codons = qw(
  TTT TCT TAT TGT TTC TCC TAC TGC TTA TCA TAA TGA
  TTG TCG TAG TGG CTT CCT CAT CGT CTC CCC CAC CGC
  CTA CCA CAA CGA CTG CCG CAG CGG ATT ACT AAT AGT
  ATC ACC AAC AGC ATA ACA AAA AGA ATG ACG AAG AGG
  GTT GCT GAT GGT GTC GCC GAC GGC GTA GCA GAA GGA
  GTG GCG GAG GGG
);

my $numcod = make_counter @codons;
print $numcod->("GAG-GGG!AGG,TAT#TTT");

请注意,任何垃圾(如果存在)必须在密码子序列之间

输出:

5