比较两个字符串的索引

比较两个字符串的索引

我有两个长度相同的双引号字符串,如下所示:

"$con"-(由空格和 * 组成):

                        *   ******       *** ** *                  **         

"$prot"- (由字母和 - 组成):

M-ASDFRMKAWRGMLMI----WSGRCYYYYHQFLIMASDFRMKAMKAWWSGRCYNSHPPAAQVFYWLGLLSDVAGSALEAQ

$prot如何提取中与 * 的位置相对应的同一位置的字母字符串$con

答案1

如果您的字符串不包含任何换行符,这里有一个仅使用 POSIX 工具的解决方案。它的工作原理是将所有字符放在单独的行上,将两个文件压缩在一起,然后提取第一个文件(现在的第一列)具有*.

con_file=$(mktemp)
echo "$con" | sed -e 's/./&\
/g' >"$con_file"
prot_lines=$(echo "$prot" | sed -e 's/./&\
/g')
prot_extract=$(echo "$prot_lines" |
               paste -d "$con_file" - |
               sed -n 's/^* //p' |
               tr -d '\n')

另一种可能更直接且无疑更快的方法是在 awk 中编写循环。

echo "$prot" | awk -v filter="$con" '{
    for (i=1; i<=length; i++) {
        if (substr(filter, i, 1) == "*") printf "%c", substr($0, i, 1);
    }
}
END {printf "\n"}'

另一种方法是将过滤器转换为索引列表。转换速度很慢,但如果每组索引都有很长的蛋白质列表,我希望这是最快的方法。

indices=$(echo "$con" |
          sed 's/\*\**/,&\n/g' |
          awk -F , 'BEGIN {start = 1}
                    /\*/ {start += length($1);
                          printf "%d-", start;
                          start += length($2);
                          printf "%d,", start - 1}')
indices=${indices%,}
echo "$prot" | cut "$indices"

答案2

您可以使用此 Perl 脚本来执行您想要的操作:

#!/usr/bin/perl

$con  ='                        *   ******       *** ** *                  **         ';
$prot ='M-ASDFRMKAWRGMLMI----WSGRCYYYYHQFLIMASDFRMKAMKAWWSGRCYNSHPPAAQVFYWLGLLSDVAGSALEAQ';

@c_con = split(//, $con);
@c_prot = split(//, $prot);

@i_con = grep { $c_con[$_] eq '*' } 0 .. $#c_con;
map { print "index: $_, value: @c_prot[$_]\n" } @i_con;

例子

运行它将在 中生成索引和这些索引处的值的列表$prot

$ ./extracvals.pl 
index: 24, value: R
index: 28, value: Y
index: 29, value: Y
index: 30, value: H
index: 31, value: Q
index: 32, value: F
index: 33, value: L
index: 41, value: M
index: 42, value: K
index: 43, value: A
index: 45, value: K
index: 46, value: A
index: 48, value: W
index: 67, value: G
index: 68, value: L

怎么运行的?

该脚本创建 2 个字符串,如 OP$con和 所描述$prot。然后将这些字符串读入 2 个数组,使得字符串中的每个字符占据数组中的一个单元格。这是使用 Perl 的split函数完成的:

@c_con = split(//, $con);
@c_prot = split(//, $prot);

2 个新数组,@c_con(contains $con) 和@c_prot(contains $prot)。

然后我们使用 Perl 的grep函数查找数组中所有@c_con值为 的索引'*'。该索引列表存储在另一个数组 中@i_con

最后我们使用 Perl 的map函数来打印给定索引处的索引值和数组中的相应值@c_prot。该map函数从 array 中获取每个值@i_con,并计算花括号中的命令:

{ print "index: $_, value: @c_prot[$_]\n" }

对于每个值。$_当我们map迭代数组 时,索引存储在 Perl 的临时变量 中@i_con

答案3

我做了一个与 slm 类似的解决方案(他比我先一步!)但是如果 OP 想要避免全部用 perl 编码:

#!/bin/sh

con="                        *   ******       *** ** *                  **"
prot="M-ASDFRMKAWRGMLMI----WSGRCYYYYHQFLIMASDFRMKAMKAWWSGRCYNSHPPAAQVFYWLGLLSDVAGSALEAQ"

# put the con and prot variables into our environment variables
export con prot

# then call perl
result=$(perl -e 'my @x = split(//, "$ENV{con}"); 
    my @i = grep { $x[$_] eq "*" } 0 .. $#x; 
    print join("", map { substr("$ENV{prot}", $_, 1) } @i );' )

# now we have your answer in $result
echo "$result"

# then once finished with con and prot, unset them from the environment
unset con prot

$ENV是 perl 中的保留变量,包含所有环境export变量名称和值,因此可以简单地通过获取 $prot 的值(我们用来设置它) $ENV{prot}

我没有像 slm 那样分割数组,而是使用substr它返回给定字符串(第一个参数)的子字符串,位于设置长度(第三个参数)的偏移量(第二个参数)处。除此之外,我们似乎使用相同的解决方案(相当诡异,暗示《暮光之城》音乐):)

答案4

使用 Bash shell 功能的简单解决方案(/bash在问题中看到了一个标签):

con="                        *   ******       *** ** *                  **"
prot="M-ASDFRMKAWRGMLMI----WSGRCYYYYHQFLIMASDFRMKAMKAWWSGRCYNSHPPAAQVFYWLGLLSDVAGSALEAQ"

i=0
# Iterate until the index is less than the con string length  
while [ $i -lt ${#con} ]
do 
    # Get the current element of the con "character array"  
    c=${con:$i:1}
    if [[ $c == '*' ]]
    then
        # Get the corresponding element from the prot character array  
        p=${prot:$i:1}
        echo $i, $c, $p
    fi
    i=$((i+1))
done

输出是:

24, *, R
28, *, Y
29, *, Y
30, *, H
31, *, Q
32, *, F
33, *, L
41, *, M
42, *, K
43, *, A
45, *, K
46, *, A
48, *, W
67, *, G
68, *, L

当然,您可以更改echo语句来控制打印的内容。

来源:Bash:将字符串拆分为字符数组

相关内容