2016-02-23 78 views
2

如何删除行中的其他行的子行,同时保留包含它们的较长字符串?删除其他行的子字符串的行

我有一个包含肽序列作为字符串的文件 - 每行一个序列字符串。我想保留包含所有序列的字符串,并删除文件中其他行的子字符串的所有行。

输入

GSAAQQYW 
ATFYGGSDASGT 
GSAAQQYWTPANATFYGGSDASGT 
GSAAQQYWTPANATF 
ATFYGGSDASGT 
NYARTTCRRTG 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 
RFTITGHDYFDN 
IVPVNYARTTCRRTG 
ARTTCRRTGGIRFTITG 

期望输出

GSAAQQYWTPANATFYGGSDASGT 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 

输出应该只保留最长的字符串,删除这是最长的字符串的子行。因此,在上面的输入中,行1,2,4和5是行3的子字符串,因此输出保留行3.类似地,行6,8,9和10上的行都是行7的子行,因此行7被保留并写入输出。

+0

什么是“长“? “两个最长”? –

+0

啊,你想删除任何字符串是另一个字符串的子字符串吗?你到目前为止尝试过什么? –

+0

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html#index-index_0028_0029-function – user3159253

回答

2

这应该做你想要什么:

$ cat tst.awk 
{ arr[$0]; strs=strs $0 RS } 
END { 
    for (str in arr) { 
     if (split(strs,tmp,str) == 2) { 
      print str 
     } 
    } 
} 

$ awk -f tst.awk file 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 
GSAAQQYWTPANATFYGGSDASGT 

它循环通过arr中的每个字符串然后使用它作为split()的分隔符值 - 如果字符串出现一次,那么完整的文件内容将被分割成一半,因此split()将返回2,但如果字符串是其他字符串的子集,那么文件内容将被拆分成多个段,因此拆分会返回一些高于2的数字。

如果一个字符串可能在输入中出现多次,并且您希望它在输出中多次打印(请参阅注释中的问题@ G.Cito下文),那么你会修改上面:

!cnt[$0]++ { strs=strs $0 RS } 
END { 
    for (str in cnt) { 
     if (split(strs,tmp,str) == 2) { 
      for (i=1;i<=cnt[str];i++) { 
       print str 
      } 
     } 
    } 
} 
+0

工作得很好!你能解释一下循环吗? –

+1

我在底部添加了一个解释 –

+0

@EdMorton所以'file'中的所有字符串,'awk'只找到并打印可以分成两部分的字符串(跳过那些不能被分割或分割多次的字符串) 。 ++不错,简单!是否有一种简单的方法来处理“长”字符串(我称之为下面更多巴洛克式perl解决方案中的“主字符串”)多次出现的情况?使用'awk'脚本和perl'%uniq'散列,它会被排除在输出之外。 –

3

可能:

input=./input_file 
while read -r str 
do 
[[ $(grep -c "$str" "$input") == 1 ]] && echo $str 
done < "$input" 

生产:

GSAAQQYWTPANATFYGGSDASGT 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 

它是缓慢的 - 但是简单..

+2

谢谢,这工作 –

-1

这将帮助你什么你到底需要:

awk'{打印长度(),NR,$ 0 | “sort -rn”}'sed_longer.txt |头-n 2

0

作为一个Perl的 “一个班轮”(这应该剪切和粘贴到终端工作):

perl -E 'chomp(@r=<>); 
     for $i (0..$#r){ 
      map { $uniq{$_}++ if (index($r[$i], $_) != -1) } @r; 
     } 
     for (sort keys %uniq){ say if ($uniq{$_} == 1); }' peptide_seq.txt 
  • 我们读诗的Chomp从标准输入文件(peptide_seq.txt)( <>)并将其保存在@r中,该数组中的每个元素都是文件中每行的字符串。

  • 接下来我们通过阵列和@rmap的元素的哈希(%uniq),其中每个key是每行的内容迭代;并且每个value是一个数字,当一行被发现是另一行的子字符串时,该数字就会增加。使用index我们可以check whether a string contains a sub-string并递增相应的散列值ifindex()不会返回“找不到”的值(-1)。

  • “主”字符串包含所有其他的字符串作为自己的子串和仅会被递增,因此,我们循环再打印%uniq哈希具有价值== 1的钥匙。这第二个循环可能是map代替:

    map { say if ($uniq{$_} == 1) } sort keys uniq ;

作为一个独立的脚本,可能是:

#!perl -l 
chomp(@r=<DATA>); 

for $i (0..$#r) { 
    map { $uniq{$_}++ if (index($r[$i], $_) != -1) } @r ; 
} 

map { print if ($uniq{$_} == 1) } sort keys %uniq ; 

__DATA__ 
GSAAQQYW 
ATFYGGSDASGT 
GSAAQQYWTPANATFYGGSDASGT 
GSAAQQYWTPANATF 
ATFYGGSDASGT 
NYARTTCRRTG 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 
RFTITGHDYFDN 
IVPVNYARTTCRRTG 
ARTTCRRTGGIRFTITG 

输出

GSAAQQYWTPANATFYGGSDASGT 
IVPVNYARTTCRRTGGIRFTITGHDYFDN 
相关问题