Tách chuỗi đơn thành mảng ký tự bằng cách sử dụng bash


9

Tôi muốn tách 'hello'thành h e l l omột mảng chỉ bằng bash, tôi có thể làm điều đó trong sed với sed 's/./& /g'nhưng tôi muốn biết làm thế nào để tách một chuỗi thành một mảng trong Bash khi tôi không biết dấu phân cách sẽ là gì, hoặc dấu phân cách là bất kỳ nhân vật duy nhất. Tôi không nghĩ rằng tôi có thể sử dụng ${i// /}mà không có một số sáng tạo vì dấu phân cách là không xác định và tôi không nghĩ biểu thức đó chấp nhận regex. Tôi đã thử sử dụng BASH_REMATCH với [[string = ~ ([az].). *]] Nhưng nó không hoạt động như tôi mong đợi. Cách thích hợp để chỉ sử dụng bash để thực hiện một string.split()loại hành vi là gì? Lý do là tôi đang cố gắng viết tiện ích rev trong tất cả 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

Nhưng tôi đã sử dụng tr và sed, tôi muốn biết làm thế nào để phân chia đúng cách và sau đó tôi sẽ sửa nó để được tất cả bash. Chỉ để cho vui.


Phải có các bản sao chéo trang trên Stack Overflow, với kích thước của nó. Một ứng cử viên là Bash: Tách chuỗi thành mảng ký tự .
Peter Mortensen

[[ $string =~ ${string//?/(.)} ]]sẽ đặt BASH_REMATCH[]theo yêu cầu, xem câu trả lời của tôi cho câu hỏi Peter Mortensen liên kết để giải thích.
mr.spuratic

Câu trả lời:


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

Đầu ra:

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

hoặc (xin lưu ý các ý kiến)

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

Đầu ra:

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

1
Cái thứ hai là tốt nhưng nó chỉ hoạt động (trong trường hợp này) vì bạn không trích dẫn "$ c", vì vậy nó sẽ giảm khoảng trắng và mở rộng các ngôi sao trong $ s.
rici

2
Tùy chọn thứ hai nên là : while read -N 1 c; do a+=("$c"); done <<< "$s". Các -Nphép để đọc dòng mới thậm chí, và các dấu ngoặc kép ("$c")tránh mở rộng tên đường dẫn (và một số vấn đề khác).

1
Tất nhiên, nếu dòng mới cuối cùng phải được sửa, hãy thay đổi dòng được cung cấp thành: while read -N 1 c; do a+=("$c"); done <<< "$s"xvà sau đó xóa dòng mới cuối cùng và thêm x : unset a[${#a[@]}-1]; unset a[${#a[@]}-1].

4

Để phân tách chuỗi thành mảng các ký tự, với dấu phân cách null, bạn có thể:

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

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

Với dấu phân cách khác null, bạn có thể:

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

Nếu IFScó thể được đặt, thì bạn chỉ có thể làm : IFS=',' arr=($str).
muru

2
@muru: Bạn sẽ bị mắc kẹt với global trong trường hợp đó. Cập nhật với vô hiệu hóa toàn cầu.
cuonglm

@BinaryZebra: Ah, vâng, trích dẫn xấu của tôi. Đã sửa nó, cảm ơn.
cuonglm

2

Chỉ để cho vui (và các vỏ khác) biến thể khác:

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

Và kiểm tra

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

sẽ in

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

0

Cách 1:

Lót:

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

Mã mở rộng:

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.

Cách 2:

Lót:

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

Mã mở rộng:

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.

Cảm ơn @cuonglm bởi gợi ý của nó.
Thực tế, bạn có thể sử dụng $REPLYđó là biến mặc định để readđọc đầu vào.


1
Bạn có thể sử dụng $REPLYthay vì charbiến.
cuonglm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.