perl 计算Fasta文件中每个种类的特定字符

mmvthczy  于 2022-11-15  发布在  Perl
关注(0)|答案(9)|浏览(137)

我一直试图在一个fasta文件中找到每个物种的1的数量,该文件如下所示:

>111
1100101010
>102
1110000001

所需的输出为:

>111
5
>102
4

我知道如何在一个文件中得到1的数字:

grep -c 1 file

我的问题是我找不到方法来记录每个物种的1的数量(而不是文件中的总数)。

uurity8g

uurity8g1#

grep -c 1将为您提供匹配 * 行 * 的数量,而不是1的总数。您可以使用grep -o使其仅在单独的行上打印每个匹配行的匹配部分,然后使用wc -l计算行数。

while read -r line
do
    if [[ ${line:0:1} == '>' ]]; then
        if [[ -n $count ]]; then
            printf "%d\n" $count
        fi
        count=0
        echo "$line"
    else
        ((count += $(grep -o 1 <<< "$line" | wc -l)))
    fi
done < fasta_file

if [[ -n $count ]]; then
    printf "%d\n" $count
fi

或者在纯bash中使用参数展开:

while read -r line
do
    if [[ ${line:0:1} == '>' ]]; then
        if [[ -n $count ]]; then
            printf "%d\n" $count
        fi
        count=0
        echo "$line"
    else
        line="${line//[^1]/}"   # remove everything but 1's
        ((count += ${#line}))   # add the length of line to count
    fi
done < fasta_file

if [[ -n $count ]]; then
    printf "%d\n" $count
fi

perl中的类似设置:

open my $fh, 'fasta_file' or die "$!";

my $count=-1;

while(<$fh>) {
    if(/^>/) {
        print "$count\n" unless($count == -1);
        $count = 0;
        print;
    } else {
        $count += tr/1//;
    }
}
print "$count\n" unless($count == -1);

close $fh;

音译运算符tr///将返回它执行了多少次音译,由于1是唯一的参数,因此它将与计算1的参数相同。

rks48beu

rks48beu2#

>111
11001010101110000001

也可以写成

>111
1100101010
1110000001

但现有的解决方案都不适用于后者。

perl -Mv5.10 -ne'
   if ( /^>/ ) {
      say $c if defined $c;
      $c = 0;
      print;
   } else {
      $c += tr/1//;
   }
   END {
      say $c if defined $c;
   }
' file.fasta

对于上面显示的两个文件,程序输出

>111
9
3bygqnnd

3bygqnnd3#

一 个 awk 创意 :

awk '
/^>/ { print ; next }              # print lines starting with ">"; skip to next input line
     { print gsub(/1/,"x") }       # replace all "1" characters with dummy "x"; gsub() returns number of replacements (ie, number of "1" characters in the line)
' file

中 的 每 一 个
或者 作为 一 句 俏皮 话 :

awk '/^>/ {print;next} {print gsub(/1/,"x")}' file

格式
折叠 成 一 个 三元 运算 符 来 确定 print

awk '{print ($0 ~ /^>/ ? $0 : gsub(/1/,"x"))}' file

格式
这些 都 产生 :

>111
5
>102
4

格式

rslzwgfq

rslzwgfq4#

假设您的fasta按照您指定的格式进行了格式化,并且假设使用awk是可以接受的,那么下面的代码可能会起作用:

while read -r one ; do 
    echo "${one}"
    read -r two
    awk -F"1" '{print NF-1}' <<< "${two}"
done <fasta.txt

(Note:awk命令按“1”拆分字符串,然后输出结果字段数减1)
fasta.txt:

>111
1100101010
>102
1110000001

输出量:

>111
5
>102
4

根据@ikegami,如果记录分布在多行上:

#!/bin/bash

fasta_file="${1:-fasta2.txt}"

while read -r line ; do 
    if [[ "$line" =~ ^\>.* ]]; then
        [[ -n "${cnt}" ]] && echo "${cnt}"
        cnt=0
        echo "${line}"
    else
       ((cnt += $(awk -F"1" '{print NF-1}' <<< "${line}") ))
    fi
done <"${fasta_file}"

[[ -n "${cnt}" ]] && echo "${cnt}"
zf9nrax1

zf9nrax15#

下面是同样适用于多行记录的gnu-awk解决方案:

cat file
>111
11001
01010
>102
1110000001

awk -v RS='>[0-9]+\n' 'NF {printf ORS "%s\n", gsub(/1/, "&")} {ORS=RT}' file
>111
5
>102
4
aydmsdu9

aydmsdu96#

使用您展示的示例,请尝试以下awk代码。在GNU awk中编写和测试,应该可以在任何awk中工作。

awk '/^>/{print;next} {print (NF?split($0,arr,"1")-1:0)}' Input_file

***说明:***简单的说明是,检查条件,如果行从>开始,则打印该行,next将跳过此处的所有后续语句。然后使用print函数,检查NF是否为NOT NULL,然后使用split函数将当前行拆分为数组arr,分隔符为1(它将提供当前行中存在的1的数量,执行-1将给予准确的计数),否则NF为NOT NULL,然后打印0(对于空行)。

yrdbyhpb

yrdbyhpb7#

要在awk的单个示例下处理一个标头上的多行数据-

$: cat fasta.txt
>101
1100101010
1111111010
1100000000
>102
1110000001
>103
1100000000
1110000001

$: awk '/^>/{if(NR>1){print cnt;} print; cnt=0;} /^[01]/{ cnt+=gsub(/1/,""); } END{print cnt;}' fasta.txt
>101
15
>102
4
>103
6

不像这里的其他版本那么优雅,但可能更容易阅读和理解。YMMV。

j8ag8udp

j8ag8udp8#

mawk -F1 '$ !NF=NF - NF^/^[>]/'
gawk -F1 '$_=NF-NF ^/^>/'      # that's the most succinct
                               # vers. I could conjure up 

>111
1100101010
>102
1110000001

5
4

如果您确实想要其他2行:

gawk -F1 '/^>/ || $_=--NF'
 mawk -F1 '/^>/ || $!_=$_=--NF' 

>111
1100101010
>102
1110000001
 
     1  >111
     2  5
     3  >102
     4  4

如果您需要多行打印机:

gawk '$_ = sprintf("%.*s%.*s\n%.f",/^[^>]/,">", (__= index($_,ORS) ) - FS, $_,
      NF-FS-substr("",__=substr($_,FS,__))-gsub(FS,"",__))' RS='\n[>]' FS=1

|

>111                                                                 
9
o8x7eapl

o8x7eapl9#

$ awk '!/>/{split($0,a,"");$0=0;for(i in a)$0+=a[i]}1' fasta.txt
>111
5
>102
4

$ awk '!/>/{for(i=sum=0;i++<length;)sum+=substr($0,i,1);$0=sum}1' fasta.txt
>111
5
>102
4

相关问题