Fractionner une chaîne unique en tableau de caractères en utilisant UNIQUEMENT bash

9

Je veux me scinder 'hello'dans h e l l oun tableau en utilisant uniquement bash, je pourrais le faire dans sed avec sed 's/./& /g'mais je veux savoir comment diviser une chaîne en un tableau dans Bash quand je ne sais pas ce que serait le délimiteur, ou le délimiteur est tout caractère unique. Je ne pense pas pouvoir l'utiliser ${i// /}sans créativité car le délimiteur est un inconnu, et je ne pense pas que cette expression accepte l'expression régulière. J'ai essayé d'utiliser BASH_REMATCH avec [[string = ~ ([az].). *]] Mais cela ne fonctionne pas comme prévu. Quelle est la bonne façon d'utiliser uniquement bash pour accomplir un string.split()type de comportement? La raison en est que j'essaie d'écrire l'utilitaire rev dans tous les bash:

  while read data; do
  word=($(echo $data|tr ' ' '_'|sed 's/./& /g'))
  new=()
  i=$((${#word[@]} - 1))
  while [[ $i -ge 0 ]]; do
    new+=(${word[$i]})
    (( i-- ))
  done
  echo ${new[@]}|tr -d ' '|tr '_' ' '
  done

Mais j'ai utilisé tr et sed, je veux savoir comment faire le split correctement et ensuite je vais le réparer pour être tout bash. Juste pour le fun.

Gregg Leventhal
la source
Il doit y avoir des doublons intersites sur Stack Overflow, compte tenu de sa taille. Un candidat est Bash: Split string en tableau de caractères .
Peter Mortensen
[[ $string =~ ${string//?/(.)} ]]sera défini BASH_REMATCH[]comme requis, voir ma réponse à la question sur laquelle Peter Mortensen établit un lien pour une explication.
mr.spuratic

Réponses:

12
s="hello"
declare -a a   # define array a
for ((i=0; i<${#s}; i++)); do a[$i]="${s:$i:1}"; done
declare -p a   # print array a in a reusable form

Production:

déclarer -aa = '([0] = "h" [1] = "e" [2] = "l" [3] = "l" [4] = "o") "

ou (veuillez noter les commentaires)

s="hello"
while read -n 1 c; do a+=($c); done  <<< "$s"
declare -p a

Production:

déclarer -aa = '([0] = "h" [1] = "e" [2] = "l" [3] = "l" [4] = "o") "
Cyrus
la source
1
Le second est sympa mais il ne fonctionne (dans ce cas) que parce que vous ne citez pas "$ c", donc il supprimera les espaces et développera les étoiles dans $ s.
rici
2
La deuxième option doit être: while read -N 1 c; do a+=("$c"); done <<< "$s". Le -Npermet de lire même les nouvelles lignes, et les guillemets ("$c")évitent l'expansion des chemins d'accès (et certains autres problèmes).
1
Bien sûr, si le dernier saut de ligne doit être corrigée, changer la ligne donnée à: while read -N 1 c; do a+=("$c"); done <<< "$s"xpuis effacer le dernier saut de ligne et x ajouté: unset a[${#a[@]}-1]; unset a[${#a[@]}-1].
4

Pour diviser la chaîne en un tableau de caractères, avec un délimiteur nul, vous pouvez:

str='hello'
arr=()
i=0
while [ "$i" -lt "${#str}" ]; do
  arr+=("${str:$i:1}")
  i=$((i+1))
done

printf '%s\n' "${arr[@]}"

Avec un délimiteur autre que null, vous pouvez:

set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%s\n' "${arr[@]}"
cuonglm
la source
Si IFSpeut être réglé, vous pouvez le faire simplement: IFS=',' arr=($str).
muru
2
@muru: Vous serez coincé avec glob dans ce cas. Mis à jour avec désactivation de glob.
cuonglm
@BinaryZebra: Ah, oui, ma mauvaise citation manquante. Corrigé, merci.
cuonglm
2

Juste pour le plaisir (et autres coquilles) autre variante:

word=hello
unset letter
while [ ${#word} -gt 0 ]
do
    rest=${word#?}
    letter[${#letter[*]}]=${word%$rest}
    word=$rest
done

Et vérifie

for l in "${!letter[@]}"
do
    echo "letter [$l] = ${letter[l]}"
done

imprimera

letter [0] = h
letter [1] = e
letter [2] = l
letter [3] = l
letter [4] = o
Costas
la source
0

Méthode 1:

Bon mot:

s="hello"
for ((i=0;i<${#s};i++)); do result[$i]="${s:i:1}"; done
echo ${result[@]}

Code développé:

s="hello"                   # Original string.

for ((i=0;i<${#s};i++)); do # For i=0; i<(length of s); i++
    result[$i]="${s:i:1}"       # result[i] is equal to the i th character of $s
done                        # End of the loop

echo ${result[@]} # Print all elements of $result.

Méthode 2:

Bon mot:

s="hello"
var=($(while read -n 1; do printf "$REPLY "; done <<< "$s"))
echo "${var[@]}"

Code développé:

s="hello" # Original string.

while read -n 1; do # Read chraracter by character the string.
    space_separated=$(printf "$space_separated $REPLY") # $space_separated is equal to it plus the current character.
done <<< "$s" # Pass the string to the loop

result=($space_separated) # Split $space_separated into an array.

echo "${result[@]}" # Print all elements of $result.

Merci à @cuonglm par sa suggestion.
En effet, vous pouvez utiliser $REPLYc'est la variable par défaut où readlit l'entrée.

Hélio
la source
1
Vous pouvez utiliser $REPLYau lieu de charvariable.
cuonglm