쉘 스크립트에서 문자열을 배열로 나누기

쉘 스크립트에서 문자열을 배열로 나누기

문자열을 배열로 변환하려고 합니다 string=11111001. 해당 배열 인덱스를 호출하여 액세스할 수 있습니다.

arr[0]=1, arr[1]=0

저는 쉘 스크립팅을 처음 접했고 읽은 내용에 구분 기호가 없어서 막혔습니다.

누구든지 나를 도와줄 수 있나요?

답변1

bash이 형식은 문자열 분할을 통해 구현되었습니다.

$ word="word"
$ printf "%s\n" "${word:0:1}"
w
$ printf "%s\n" "${word:1:1}"
o

구문은 ${variable:start:length}이며 다음을 반환합니다.length다음으로 시작하는 문자startᵗʰ 문자(0 인덱스).

$ printf "%s\n" "${word:2:2}"
rd

답변2

완전성을 위해 ,를 사용하여 zsh문자열을 다음과 같이 분할합니다.

그것은특징요소:

chars=( ${(s[])string} )

( $string유효한 문자의 일부를 형성하지 않는 바이트가 포함된 경우 각 바이트는 여전히 별도의 요소로 저장됩니다.)

그것은바이트요소

동일한 작업을 수행할 수 있지만 설정을 해제한 후에는멀티바이트예를 들어 로컬 익명 함수의 옵션:

(){ set -o localoptions +o multibyte
  bytes=( ${(s[])string} )
}

그것은문자소 클러스터요소.

PCRE의 기능을 사용하여 다음과 결합할 수 있습니다 \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
}

(입력에 로케일의 문자 맵에서 올바르게 인코딩된 텍스트가 포함되어 있다고 가정).


의 경우 string=$'Ste\u0301phane'다음이 제공됩니다.

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 )

e+U+0301 자소 클러스터(디스플레이 장치는 일반적으로 é사전 구성된 U+00E9와 동일하게 표시됨)가 2개의 문자(U+0065 및 U+0301)로 구성되므로 문자 맵 로케일로 UTF-8을 사용합니다 . 첫 번째는 1바이트(0x65)로 인코딩되고 두 번째는 2바이트(0xcc 0x81, Meta-L 및 Meta-Ctrl-A라고도 함)로 인코딩됩니다.

ASCII 문자(예: 귀하의 문자)로만 구성된 문자열의 경우 11111001이 세 문자는 동일합니다.

ksh/bash를 제외한 다른 모든 쉘에서와 마찬가지로 배열 인덱싱 은 zsh0이 아닌 1에서 시작됩니다.

답변3

문자열을 개별 문자로 분할할 수 있습니다.

string=11111001
echo "$string" | grep -o .

배열로 다시 읽습니다.

readarray -t arr <<<"$(grep -o . <<<"$string")"

그러면 물론 모든 문자가 arr배열의 모든 인덱스에 있게 됩니다.

$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")

하지만 bash가 각 개별 문자에 직접 액세스할 수 있다면 왜 새 배열을 만들어야 할까요? 다음과 같이:

$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1

${parameter:offset:length}에 대해 읽다 man bash.

답변4

bash4.4 이상 에서는 bash변수에 NUL 문자를 저장할 수 없으므로 다른 유틸리티를 호출하여 분할을 수행하고 NUL로 구분된 결과를 인쇄할 수 있습니다 readarray -td ''. .

시스템이 GNU 구현과 함께 제공되는 경우 grep다음을 수행할 수 있습니다.

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')

첫 번째를 제외하고 모두 로케일에서 유효한 문자의 일부를 형성하지 않는 바이트를 건너뜁니다(적어도 GNU grep3.4에서는). 예를 들어 string=$'Ste\u0301phane \\\xf0\x80z.'UTF-8 로케일(후행 부분은 유효한 UTF-8을 형성하지 않음)에서는 다음이 제공됩니다.

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]=".")

GNU 시스템이 아니고 $string유효한 UTF-8 텍스트가 포함되어 있다고 가정하면 다음을 사용할 수 있습니다 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")

관련 정보