
Estou tentando converter uma string, por exemplo, string=11111001
em um array que poderei acessar chamando o respectivo índice do array, como
arr[0]=1, arr[1]=0
Sou novo em scripts de shell e pelo que li, ele não tem um separador, estou travado.
Alguém pode me ajudar?
Responder1
bash
já tem uma forma disso por meio de fatiamento de string:
$ word="word"
$ printf "%s\n" "${word:0:1}"
w
$ printf "%s\n" "${word:1:1}"
o
A sintaxe para isso é ${variable:start:length}
e retornará o próximolength
personagens começando nostart
Caractere ᵗʰ (indexado em zero).
$ printf "%s\n" "${word:2:2}"
rd
Responder2
Para completar, com zsh
, para dividir uma string em:
isso épersonagemconstituintes:
chars=( ${(s[])string} )
(se $string
contiver bytes que não façam parte de caracteres válidos, cada um deles ainda será armazenado como elementos separados)
isso ébyteconstituintes
você pode fazer o mesmo, mas depois de desativar omultibyteopção, por exemplo localmente em uma função anônima:
(){ set -o localoptions +o multibyte
bytes=( ${(s[])string} )
}
isso écluster de grafemaconstituintes.
Você pode usar a capacidade do PCRE para combiná-los com \X
:
zmodload zsh/pcre
(){
graphemes=()
local rest=$string match
pcre_compile -s '(\X)\K.*'
while pcre_match -v rest -- "$rest"; do
graphemes+=($match[1])
done
}
(isso pressupõe que a entrada contém texto devidamente codificado no charmap do local).
Com string=$'Ste\u0301phane'
, aqueles dão:
chars=( S t e ́ p h a n e )
bytes=( S t e $'\M-L' $'\M-\C-A' p h a n e )
graphemes=( S t é p h a n e )
Como o e
cluster de grafema + U+0301 (cujos dispositivos de exibição geralmente representam o mesmo que o é
equivalente pré-composto U+00E9) é composto de 2 caracteres (U+0065 e U+0301) onde em localidades usando UTF-8 como seu charmap, o primeiro é codificado em um byte (0x65) e o segundo em dois bytes (0xcc 0x81, também conhecido como Meta-L e Meta-Ctrl-A).
Para strings compostas apenas por caracteres ASCII como your 11111001
, todos os três serão equivalentes.
Observe que, zsh
como em todos os outros shells, exceto ksh/bash, os índices do array começam em 1, não em 0.
Responder3
Você pode dividir a string em caracteres individuais:
string=11111001
echo "$string" | grep -o .
e leia-os de volta como uma matriz:
readarray -t arr <<<"$(grep -o . <<<"$string")"
Então, é claro, cada caractere estaria em cada índice do arr
array.
$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")
Mas por que criar um novo array se o bash pudesse acessar cada caractere individual diretamente assim:
$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1
Leia sobre ${parameter:offset:length}
em man bash
.
Responder4
Com bash
4.4+, como bash
não é possível armazenar caracteres NUL em suas variáveis, você pode chamar um utilitário diferente para fazer a divisão e imprimir o resultado delimitado por NUL, que pode ser lido em um array com readarray -td ''
.
Se o seu sistema vier com a implementação GNU do grep
, você poderia fazer:
readarray -td '' bytes < <(printf %s "$string" | LC_ALL=C grep -zo .)
readarray -td '' chars < <(printf %s "$string" | grep -zo .)
readarray -td '' graphemes < <(printf %s "$string" | grep -zPo '\X')
Todos, exceto o primeiro, irão pular bytes que não fazem parte de caracteres válidos no código do idioma (pelo menos com GNU grep
3.4). Por exemplo, com string=$'Ste\u0301phane \\\xf0\x80z.'
(a parte final não formando UTF-8 válido), em um código de idioma UTF-8, isso fornece:
declare -a bytes=([0]="S" [1]="t" [2]="e" [3]=$'\314' [4]=$'\201' [5]="p" [6]="h" [7]="a" [8]="n" [9]="e" [10]=" " [11]="\\" [12]=$'\360' [13]=$'\200' [14]="z" [15]=".")
declare -a chars=([0]="S" [1]="t" [2]="e" [3]="́" [4]="p" [5]="h" [6]="a" [7]="n" [8]="e" [9]=" " [10]="\\" [11]="z" [12]=".")
declare -a graphemes=([0]="S" [1]="t" [2]="é" [3]="p" [4]="h" [5]="a" [6]="n" [7]="e" [8]=" " [9]="\\" [10]="z" [11]=".")
Se não estiver em um sistema GNU, e assumindo que $string
contém texto UTF-8 válido, você poderia usar perl
:
readarray -td '' bytes < <(perl -0le 'print for split "", shift' -- "$string")
readarray -td '' chars < <(perl -CSA -0le 'print for split "", shift' -- "$string")
readarray -td '' graphemes < <(perl -CSA -0le 'print for shift =~ /\X/g' -- "$string")