如何计算字符串中n个字符长度组合的出现次数

时间:2016-08-02 16:46:23

标签: bash perl permutation

我使用以下一个衬垫来列出ATCG组合的出现,形成长度为6的字符串。除了不打印0匹配的出现之外,它还可以正常工作。有没有办法将正则表达式或其他部分更改为打印“0 ATTTAG”之类的内容?

#!/bin/bash
for file in e_coli.fa
do
    base=$(basename $file .fa)
    cat $file | perl -nE 'say for /(?<=([ATCG]{6}))/g' \
        | sort | uniq -c >> ${base}_hexhits_6mer.txt
done

stdout:
    465 AAAAAA
    607 AAAAAC
    661 AAAAAG
    581 AAAAAT
    563 AAAACA
    807 AAAACC
    770 AAAACG
    373 AAAACT
    663 AAAAGA
   1213 AAAAGC

4 个答案:

答案 0 :(得分:1)

由于uniq -c计算一行发生的次数,因此它不可能返回0.请求的更改需要完全重写。

perl -e'
   while (<>) {
      ++$counts{$_} for /(?=([ATCG]{6}))/g;
   }

   for my $seq (glob("{A,C,G,T}" x 6)) {
      printf("%7d %s\n", $counts{$seq}, $seq);
   }
' "$file" >"${base}_hexhits_6mer.txt"

答案 1 :(得分:1)

最简单的方法是为每个模式构建一个出现次数的哈希值,然后打印所有可能模式的计数

该程序使用glob技巧生成由A,T,C和G组成的所有可能的六字符串的列表

use strict;
use warnings 'all';

my @files = qw/ e_coli.fa /;

my %counts;

for my $file ( @files ) {

    open my $fh, '<', $file or die qq{Unable to open "$file" for input: $!};

    while ( <$fh> ) {
        ++$counts{$1} while /(?= ( [ATCG]{6} ) ) /gx;
    }
}

for my $pattern ( glob '{A,T,C,G}' x 6 ) {
    printf "%4d %s\n", $counts{$pattern} // 0, $pattern;
}

答案 2 :(得分:1)

如果您有大量数据并且需要更快的速度,那么这就是C解决方案:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void reader(FILE* in, unsigned long hist[4096]) {
  for (unsigned long key=0, count=0;;) {
    switch(getc(in)) {
      case EOF:                      return;
      case 'A': key <<= 2;           break;
      case 'C': key <<= 2; key += 1; break;
      case 'G': key <<= 2; key += 2; break;
      case 'T': key <<= 2; key += 3; break;
      default:  count=0;             continue;
    }
    if (count == 5) ++hist[key & 0xFFF];
    else ++count;
  }
}

int putkey(FILE* out, unsigned long key) {
  char s[6];
  for (int j=6; j--; key >>= 2) s[j] = "ACGT"[key&3];
  return fprintf(out, "%.6s", s); 
}

void writer(FILE* out, unsigned long hist[4096]) {
  for (unsigned long key = 0; key < 4096; ++key) {
    fprintf(stdout, "%7lu ", hist[key]);
    putkey(out, key);
    putchar('\n');
  }
}

int main(int argc, char** argv) {
  FILE* in = stdin;
  if (argc > 1) in = fopen(argv[1], "r");
  if (!in) { perror(argv[1]); exit(1); }
  unsigned long hist[4096] = {0};
  reader(in, hist);
  writer(stdout, hist);
  return 0;
}

处理一个31MB的fastq样本(其中包括所有4096个可能的六字符序列)需要不到半秒的时间; Perl解决方案分别需要12秒(fugu)和18秒(ikegami / borodin)。

答案 3 :(得分:0)

你要做的事情要复杂得多。要了解您没有看到的内容,您需要首先了解所有可能的组合字符,然后您可以对其进行过滤。

在这里,我使用Perl中的substr滑动窗口方法来查找ATCGAs,{{字符串中的所有“看到的”Ts字符。哈希中的1}}和Cs(从Gs读取)。然后对它们进行分类,以便首先显示最常见的6聚体并打印出来。

__DATA__

显然,计算字符串中所有字符排列的方式比我做的更好/更漂亮,但它有效。

正如鲍罗丁所说,这主要打印出“看不见的”字符串的变化。