删除作为其他行的子串的行

时间:2016-02-23 00:31:40

标签: string perl awk sed substring

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

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

输入

GSAAQQYW
ATFYGGSDASGT
GSAAQQYWTPANATFYGGSDASGT
GSAAQQYWTPANATF
ATFYGGSDASGT
NYARTTCRRTG
IVPVNYARTTCRRTGGIRFTITGHDYFDN
RFTITGHDYFDN
IVPVNYARTTCRRTG
ARTTCRRTGGIRFTITG

预期输出

GSAAQQYWTPANATFYGGSDASGT
IVPVNYARTTCRRTGGIRFTITGHDYFDN

输出应该只保留最长的字符串并删除所有作为最长字符串的子字符串的行。因此,在上面的输入中,第1,2,4和5行是第3行的子串,因此输出保留第3行。类似于第6,8,9和10行的字符串,所有字符串都是第7行的子字符串,因此行保留7并将其写入输出。

4 个答案:

答案 0 :(得分:3)

也许:

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

产生

GSAAQQYWTPANATFYGGSDASGT
IVPVNYARTTCRRTGGIRFTITGHDYFDN

它很慢 - 但很简单......

答案 1 :(得分: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
            }
        }
    }
}

答案 2 :(得分:1)

作为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
  • 我们从STDIN(peptide_seq.txt)读取并选择文件(<>)并将其保存在@r中,这将是一个数组,其中每个元素都是来自的字符串文件中的每一行。

  • 接下来,我们遍历数组并map@r的元素迭代到散列(%uniq),其中每个key是每行的内容;每个value是一个数字,当一条线被发现是另一条线的子串时,该数字会递增。使用index我们check whether a string contains a sub-string并增加相应的哈希值if index()不会返回“未找到”(-1)的值。

  • “master”字符串包含所有其他字符串作为其自身的子字符串,并且只会增加一次,因此我们再次循环以打印具有值{%uniq哈希的键。 {1}}。第二个循环可以是== 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

答案 3 :(得分:-1)

这将帮助您完全需要:

awk'{print length(),NR,$ 0 | “sort -rn”}'sed_longer.txt |头-n 2