![Divida la cadena en una matriz en el script de shell](https://rvso.com/image/192230/Divida%20la%20cadena%20en%20una%20matriz%20en%20el%20script%20de%20shell.png)
Estoy intentando convertir una cadena, por ejemplo, string=11111001
en una matriz a la que podré acceder llamando al índice de matriz respectivo como
arr[0]=1, arr[1]=0
Soy nuevo en los scripts de shell y, por lo que leí, no tiene separador. Estoy atascado.
¿Alguien me puede ayudar?
Respuesta1
bash
ya tiene una forma de esto mediante corte de cuerdas:
$ word="word"
$ printf "%s\n" "${word:0:1}"
w
$ printf "%s\n" "${word:1:1}"
o
La sintaxis para esto es ${variable:start:length}
y devolverá el siguientelength
personajes comenzando en elstart
Carácter ᵗʰ (indexado a cero).
$ printf "%s\n" "${word:2:2}"
rd
Respuesta2
Para completar, con zsh
, para dividir una cadena en:
espersonajeconstituyentes:
chars=( ${(s[])string} )
(Si $string
contiene bytes que no forman parte de caracteres válidos, cada uno de ellos se almacenará como elementos separados)
esbyteconstituyentes
puedes hacer lo mismo pero después de haber desarmado elmultibyteopción, por ejemplo localmente en una función anónima:
(){ set -o localoptions +o multibyte
bytes=( ${(s[])string} )
}
esgrupo de grafemasconstituyentes.
Puede utilizar la capacidad de PCRE para combinarlos con \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
}
(se supone que la entrada contiene texto correctamente codificado en el mapa de encanto de la configuración regional).
Con string=$'Ste\u0301phane'
, esos dan:
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 el e
grupo de grafemas + U+0301 (que los dispositivos de visualización generalmente representan lo mismo que el é
equivalente precompuesto U+00E9) se compone de 2 caracteres (U+0065 y U+0301), donde en las configuraciones regionales que usan UTF-8 como su mapa de encanto, el primero está codificado en un byte (0x65) y el segundo en dos bytes (0xcc 0x81, también conocido como Meta-L y Meta-Ctrl-A).
Para cadenas formadas únicamente por caracteres ASCII como su 11111001
, los tres serán equivalentes.
Tenga en cuenta que, zsh
al igual que en todos los demás shells excepto ksh/bash, los índices de matriz comienzan en 1, no en 0.
Respuesta3
Podrías dividir la cadena en caracteres individuales:
string=11111001
echo "$string" | grep -o .
y leerlos como una matriz:
readarray -t arr <<<"$(grep -o . <<<"$string")"
Entonces, por supuesto, cada carácter estaría en cada índice de la arr
matriz.
$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")
Pero, ¿por qué crear una nueva matriz si bash puede acceder a cada carácter individual directamente de esta manera?
$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1
Lea sobre ${parameter:offset:length}
en man bash
.
Respuesta4
Con bash
4.4+, como bash
de todos modos no se pueden almacenar caracteres NUL en sus variables, se puede llamar a una utilidad diferente para realizar la división e imprimir el resultado delimitado por NUL, que se puede leer en una matriz con readarray -td ''
.
Si su sistema viene con la implementación GNU de grep
, podría hacer:
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 menos el primero omitirán bytes que no formen parte de caracteres válidos en la configuración regional (al menos con GNU grep
3.4). Por ejemplo, con string=$'Ste\u0301phane \\\xf0\x80z.'
(la parte final no forma UTF-8 válido), en una configuración regional UTF-8, eso da:
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]=".")
Si no está en un sistema GNU, y suponiendo que $string
contenga texto UTF-8 válido, podría usar perl
en su lugar:
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")