如何创建子字符串数组

如何创建子字符串数组

假设我有一个变量序列,它是一个字符串。

> sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"

我想创建一个数组,比如 seq,其中每个元素都是初始序列的 3 个字符子字符串,所以类似于

echo $seq[1]
echo $seq[2]
echo $seq[n]

给出:

AAA  
GCA
TAG

其中 n 是数组的最后一个元素。有人可以编写脚本来执行此操作吗?这是我想要做的 unix 和 C++ 代码的奇怪组合,但我需要它全部是 unix

sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
array_name=(seq) while($i+2<length(sequence)) {
seq[i]=substring(sequence,i,3)  i=i+3 }

答案1

假设您在以下位置执行此操作bash

sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"

for (( i = 0; i < ${#sequence}; i += 3 )); do
    printf '%s\n' "${sequence:i:3}"
done

这会迭代序列的长度,一次三个碱基对。在每次迭代中,打印下一组三个碱基。

要将它们放入数组中,seq而不是将它们打印出来:

sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"

for (( i = 0; i < ${#sequence}; i += 3 )); do
    seq+=( "${sequence:i:3}" )
done

这给了你数组seq。各个数组元素可用作"${seq[0]}""${seq[1]}"等。

为了得到另外两个阅读框,更改循环,使其从 1 或 2 开始。

答案2

在 中bash,使用循环和索引处理长字符串可以是非常速度很慢,作为替代方案,您可以使用read字符串并构建一个数组:

sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"

declare -a seq=( "" )
while read -n 3 -r triple ; do seq+=( "$triple" ); done <<< "$sequence"
declare -p seq

该数组是使用空字符串的索引 0 创建的,因此您的索引按照要求从 1 开始。

其工作方式是使用“ read -n 3”一次读取三个字符到变量中triple,将其添加到数组(+=)中,使用<<<重定向来呈现序列stdinread处理输入不是 3 的倍数的情况。

(如上面的编码,这很适合读取不间断的字母序列——这不是通用的“分割”例程,因为它没有对空格、转义字符、nul 字节等进行特殊处理。如果你设置了,IFS=""那么read将在如果您需要从输入中删除空格,可以使用... <<< ${sequence// /}.

这是更普遍问题的一个特例 在 Bash 中将字符串拆分为数组,其中您还可以阅读有关粗心程序员的所有令人兴奋的陷阱。 )

答案3

如果您的字符串不包含空格或换行符,您可以使用grep分隔字符串并创建一个数组:

sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
seq=( $(printf '%s' "$sequence" | grep -o ... ) )

或使用fold代替grep

seq=( $(printf '%s' "$sequence" | fold -b3 ) )

与 相比grep,这将使最后一个字符 ( G) 也成为数组元素。


笔记:如果您的字符串包含*,这在某些情况下可能会导致问题。例如,如果您在当前工作目录中seq=( AT* ATA ATG )有以 开头的文件名,它将扩展为文件名。AT您可以使用set -o noglob它来防止通配符。

更好的选择: 使用 readarray而不是seq=(...):

readarray seq < <(printf '%s' "$sequence" | fold -b3 )

(归功于@Kusalananda)

相关内容