Dividi singola stringa in una matrice di caratteri usando SOLO bash


9

Voglio dividere 'hello'in h e l l oun array usando solo bash, potrei farlo in sed con sed 's/./& /g'ma voglio sapere come dividere una stringa in un array in Bash quando non so quale sarebbe il delimitatore, o il delimitatore è qualsiasi personaggio unico. Non credo di poter usare ${i// /}senza un po 'di creatività perché il delimitatore è sconosciuto e non credo che l'espressione accetti regex. Ho provato a utilizzare BASH_REMATCH con [[string = ~ ([az].). *]] Ma non funziona come mi aspettavo. Qual è il modo corretto di usare solo bash per realizzare un string.split()tipo di comportamento? Il motivo è che sto cercando di scrivere l'utilità rev in tutta 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

Ma ho usato tr e sed, voglio sapere come eseguire correttamente la divisione e poi lo aggiusterò per essere tutto bash. Solo per divertimento.


Devono essere presenti duplicati tra siti su Stack Overflow, date le dimensioni. Un candidato è Bash: dividere la stringa in una matrice di caratteri .
Peter Mortensen,

[[ $string =~ ${string//?/(.)} ]]verrà impostato BASH_REMATCH[]come richiesto, vedere la mia risposta alla domanda a cui Peter Mortensen si collega per una spiegazione.
mr.spuratic,

Risposte:


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

Produzione:

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

oppure (notare i commenti)

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

Produzione:

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

1
Il secondo è carino ma funziona (in questo caso) solo perché non citi "$ c", quindi lascerà cadere gli spazi bianchi ed espanderà le stelle in $ s.
rici,

2
La seconda opzione dovrebbe essere: while read -N 1 c; do a+=("$c"); done <<< "$s". Il -Npermette di leggere a capo anche, e le quotazioni ("$c")evitare l'espansione del percorso (e alcuni altri problemi).

1
Naturalmente, se l'ultima nuova riga deve essere corretto, modificare la linea dato a: while read -N 1 c; do a+=("$c"); done <<< "$s"xe quindi cancellare l'ultima riga e il x aggiunto: unset a[${#a[@]}-1]; unset a[${#a[@]}-1].

4

Per dividere la stringa in una matrice di caratteri, con delimitatore nullo, è possibile:

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

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

Con delimitatore diverso da null, è possibile:

set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%s\n' "${arr[@]}"

Se IFSpuò essere impostato, allora si può solo fare: IFS=',' arr=($str).
muru,

2
@muru: Sarai bloccato con glob in quel caso. Aggiornato con disabilitazione glob.
cuonglm,

@BinaryZebra: Ah, sì, la mia brutta citazione mancante. Risolto, grazie.
cuonglm,

2

Solo per divertimento (e altre conchiglie) altra variante:

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

E controlla

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

stamperà

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

0

Metodo 1:

Oneliner:

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

Codice espanso:

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.

Metodo 2:

Oneliner:

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

Codice espanso:

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.

Grazie a @cuonglm dal suo suggerimento.
In effetti, è possibile utilizzare $REPLYquesta è la variabile predefinita in cui readlegge l'input.


1
Puoi usare al $REPLYposto della charvariabile.
cuonglm,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.