Как создать массив подстрок

Через grep, если несколько раз подряд:

grep -oP '(?<=<td>).*?(?=</td>)' infile.txt
1
6

Через awkи то же самое, если несколько раз подряд:

awk -v FS="(<td>|</td>)" '{for(i=2;i<=NF;i+=2) print $I}' infile.txt
0
14.10.2019, 12:39
3 ответа

Предположим, что вы делаете это в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.

3
28.01.2020, 02:14

Если ваша строка не содержит пробелов или новых строк, вы можете использовать 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)

2
28.01.2020, 02:14

В 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, добавьте ее в массив (+=), используя перенаправление <<<для представления последовательности в stdin. ]. readобрабатывает случаи, когда ввод не кратен 3.

(Как показано выше, это хорошо для чтения неразрывных последовательностей букв — это не универсальная процедура «разделения», поскольку она не имеет специальной обработки пробелов, escape-символов, нулевых байтов и т. д. Если вы установите IFS="", то readсохранит пробелы во входных данных. Если вам нужно удалить пробелы из ввода, вы можете использовать ... <<< ${sequence// /}.

Это частный случай более общей задачи Разделить строку на массив в Bash , где вы также можете прочитать обо всех интересных ловушках для неосторожного программиста.)

1
28.01.2020, 02:14

Теги

Похожие вопросы