извлекать каждый n-й символ из строки

Я пытаюсь найти решение для этого вопроса. До сих пор мой подход к этой проблеме следующий.

  • Добавьте все символы вместе, чтобы сделать длинную строку.
  • После указанного выше действия удалите все пробелы или области табуляции, чтобы у нас была только одна большая строка.

Я смог установить вышеуказанные шаги с помощью команды ниже.

column -s '\t' inputfile | tr -d '[:space:]' 

Поэтому для входного файла, подобного этому,

 1 0 0 0 0 0 0 1 1 1 0 0 

После применения вышеуказанной команды у меня есть значения как,

 100000011100 

Теперь в этой большой строке я пытаюсь применить подход, как показано ниже.

Извлеките каждый 6- й символ (как захочет оригинальный OP) и добавьте его к элементу массива до конца строки.

Таким образом, в основном, с вышеуказанным шагом, я пытаюсь создать элементы массива,

10 (1- й и 7- й символы), 01 (2- й и 8- й символы), 01 (3- й и 9- й символы), 01 (4- й и 10- й символы), 00 (5- й и 11- й символы) 00 (6- й и 12- й символы).

Поэтому мой вопрос: как я мог извлечь каждый n- й символ, чтобы я мог добавить их в массив, чтобы продолжить? (n = 6, в этом случае).

4 Solutions collect form web for “извлекать каждый n-й символ из строки”

Две линии

Вот решение pure- bash которое создает массив bash :

 s="100000011100" array=($( for ((i=0; i<${#s}-6; i++)) do echo "${s:$i:1}${s:$((i+6)):1}" done )) echo "${array[@]}" 

Это дает тот же результат, что и в вопросе:

 10 01 01 01 00 00 

Ключевым элементом здесь является использование расширения подстроки bash. Bash позволяет извлекать подстроки из переменной, например parameter , через ${parameter:offset:length} . В нашем случае смещение определяется переменной цикла i а длина всегда равна 1 .

Общее решение для любого количества строк

Предположим, например, что наша исходная строка имеет 18 символов, и мы хотим извлечь i-й, i + 6-й и i + 12-й символы для i от 0 до 5. Тогда:

 s="100000011100234567" array=($( for ((i=0; i<6; i++)) do new=${s:$i:1} for ((j=i+6; j<${#s}; j=j+6)) do new="$new${s:$j:1}" done echo "$new" done )) echo "${array[@]}" 

Это дает результат:

 102 013 014 015 006 007 

Этот же код распространяется на произвольное число 6-символьных строк. Например, если s имеет три строки (18 символов):

 s="100000011100234567abcdef" 

Затем выход становится:

 102a 013b 014c 015d 006e 007f 

Использование perl :

 $ echo 100000011100 | perl -nle ' for ($i = 0; $i < length()/2; $i++) { print substr($_,$i,1), substr($_,$i+6,1); } ' 10 01 01 01 00 00 

Он работает для двух линий. Если вы хотите работать с произвольными строками, вы должны обрабатывать строки напрямую, а не строить большую строку. С этим вводом:

 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 

Пытаться:

 $ perl -anle ' for ($i = 0; $i <= $#F; $i++) { push @{$h{$i}}, $F[$i]; } END { print @{$h{$_}} for keys %h; } ' file 000 010 000 100 010 010 

Как решение оболочки, getopts , вероятно, проще всего. Что касается getopts это то, что именно POSIX задает именно то, что вы просите, – обрабатывайте байт-поток в оболочном цикле. Я знаю, это звучит странно, потому что, если вы похожи на меня, прежде чем я узнал об этом, вы, вероятно, думаете, ну, да, я думал, что он должен обрабатывать ключи командной строки. Это правда, но это первое. Рассматривать:

 -thisisonelongstringconsistingofseparatecommandlineswitches 

Да, getopts должен это обработать. Он должен разбить этот char на char в цикле и вернуть вам каждый символ либо в переменную оболочки $OPTARG либо в другую, которую вы определяете по имени, в зависимости от того, как конкретно вы получаете, когда вы его вызываете. Более того, он должен возвращать ошибки в переменных оболочки и сохранять свои успехи, когда это происходит в переменной оболочки $OPTIND чтобы она могла возобновиться в том месте, где она была $OPTIND если вы можете как-то ее решить. И он должен выполнять всю работу без вызова одной подоболочки.

Итак, скажем, у нас есть:

 arg=$(seq -s '' 1000); set -- while getopts :0123456789 v -"${arg}" do [ "$((i=$i+1<6?$i+1:0))" -gt 0 ] || set "$@" "$v" done 

Хммм … Интересно, работает ли это?

 echo "$((${#arg}/6))" "$#" 482 482 

Это мило…

 eval ' printf %.1s\\n "${arg#'"$(printf %0$((124*6-1))d | tr 0 \?)"'}" "${124}"' 4 4 

Итак, как вы можете видеть, команда getopts полностью устанавливает массив для каждого шестого байта в строке. И это не должно быть чисел, подобных этому, и даже не должно быть символами безопасности оболочки, и вам даже не нужно указывать целевые символы, как я сделал выше, с 01234565789 . Я тестировал это много раз во множестве оболочек, и все они просто работают. Есть некоторые причуды – bash выбрасывает первый символ, если он является символом пробела, – dash принимает : двоеточие в качестве заданного параметра, даже если это просто единственное, что запрещает использование POSIX. Но ничто из этого не имеет значения, поскольку getopts прежнему откладывает текущее значение opt char в $OPTARG даже когда он возвращает вам ошибку (представленную «назначенной вашему выбранному оптору var»), а в противном случае явно отключает $OPTARG если вы не объявили опцию есть аргумент. И простейшая вещь – это хорошая вещь – она ​​только отбрасывает ведущее пространство, что отлично, потому что при работе с неизвестными значениями вы можете делать:

 getopts : o -" $unknown_value" 

… для запуска цикла без какой-либо опасности того, что первый символ фактически находится в вашей принятой строке args, что приведет к тому, что getopts заклеивать все в $OPTARG – в качестве аргумента.

Вот еще один пример:

 OPTIND=1 while getopts : o -" $(dd if=/dev/urandom bs=16 count=1 2>/dev/null)" do printf '\\%04o' "'$OPTARG"; done \0040\0150\0071\0365\0320\0070\0161\0064\0274\0115\0012\0215\0222\0271\0146\0057\0166 

Я устанавливаю $OPTIND=1 в первой строке, потому что я просто использовал getopts и, пока вы его не перезагрузите, он ожидает, что его следующий вызов продолжится там, где он остановился, – он хочет "${arg2}" другими словами. Но я не хочу давать, и теперь я делаю совсем другое дело, поэтому я дал понять, сбросив $OPTIND в этот момент это хорошо.

В этом я использовал zsh – который не капитулирует о ведущем пространстве – и поэтому первый символ – это восьмеричный 40 – пробельный символ. Я обычно не использую getopts таким образом, хотя, как правило, я использую его, чтобы избежать write() для каждого байта и вместо этого назначать свой вывод – который входит в переменную – другой переменной оболочки – как я уже делал выше с set после моды. Затем, когда я буду готов, я могу взять всю строку и, когда я обычно разбиваю первый байт.

sed – это первое, что приходит мне в голову.

 $ echo 1234567890abcdefghijklmnopqrstuvwxyz | sed 's/.\{5\}\(.\)/\1/g' 6bhntz 

Сопоставьте 5 персонажей, захватите 6-й и замените их всем этим захваченным персонажем.

Это, однако, будет иметь проблему, если длина строки не является точной кратной 6:

 $ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{5\}\(.\)/\1/g' 6bhntuvwxy 

Но мы можем исправить это, немного изменив sed :

 $ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{1,5\}\(.\{0,1\}\)/\1/g' 6bhnt 

Из-за жадного характера регулярного выражения, совпадения переменной длины будут соответствовать столько, сколько они могут, и если для захвата ничего не осталось, то оно не захватывается, и символы просто удаляются.

  • Solaris «чистые» групповые файлы (или, в любом случае, любой текстовый файл)
  • Как измерить скорость чтения / записи раздела или диска?
  • regexp в ksh для расширений tgz, tar.tgz
  • Сценарий оболочки для увеличения количества записей
  • проблемы с GNU tail -f и комбинацией команд
  • Как копировать и переименовывать файлы, найденные в функции «найти» Linux?
  • Выбирайте только каталоги и порядок с помощью эха
  • Grep для строки в первой строке всех файлов в каталоге и потомках
  • grepping переменная и добавление 1 к ней
  • Есть ли версия команды «Найти», которая сохраняет свое состояние?
  • Простой вопрос: lftp не пишет в $ LOG - что я делаю неправильно?
  • Linux и Unix - лучшая ОС в мире.