두 문자열의 인덱스 비교

두 문자열의 인덱스 비교

다음과 같이 길이가 같은 두 개의 큰따옴표 문자열이 있습니다.

"$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

어떻게 작동하나요?

스크립트는 $conOP 및 에 설명된 대로 2개의 문자열을 생성합니다 $prot. 그런 다음 이러한 문자열을 2개의 배열로 읽어서 문자열의 각 문자가 배열의 한 셀을 차지하도록 합니다. 이는 splitPerl의 기능을 사용하여 수행됩니다.

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

2개의 새로운 배열, @c_con( 포함 $con) 및 @c_prot( 포함 $prot).

그런 다음 Perl의 함수를 사용하여 값이 .인 배열의 grep모든 인덱스를 찾습니다 . 이 인덱스 목록은 다른 배열에 저장됩니다 .@c_con'*'@i_con

마지막으로 우리는 Perl의 map함수를 사용하여 주어진 인덱스의 인덱스 값과 배열의 해당 값을 인쇄합니다 @c_prot. 이 map함수는 배열에서 각 값을 가져와 @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

$ENVPerl의 예약된 변수이며 모든 항목을 포함합니다.환경export변수 이름과 값. $prot(설정하는 데 사용) 값을 간단히 얻을 수 있습니다 $ENV{prot}.

slm처럼 배열을 분할하는 대신 substr이를 사용하여 설정된 길이(세 번째 인수)에서 오프셋(두 번째 인수)으로 지정된 문자열(첫 번째 인수)의 하위 문자열을 반환합니다. 그 외에는 동일한 솔루션을 사용하는 것 같습니다(꽤 이상합니다. Twilight 음악에 대한 힌트가 있습니다.):)

답변4

Bash 쉘 기능을 사용하는 간단한 솔루션( /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: 문자열을 문자 배열로 분할

관련 정보