在shell脚本中将字符串分解为数组

在shell脚本中将字符串分解为数组

我正在尝试将字符串转换string=11111001为数组,我可以通过调用相应的数组索引来访问它,例如

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

我是 shell 脚本新手,从我读到的内容来看,它没有分隔符,我陷入了困境。

有人能帮我吗?

答案1

bash已经通过字符串切片的方式实现了这种形式:

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

其语法为${variable:start:length}, 并将返回下一个length字符开始于startᵗʰ 字符(零索引)。

$ 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 作为其字符映射的语言环境中,第一个在一个字节 (0x65) 上编码,第二个在两个字节 (0xcc 0x81,也称为 Meta-L 和 Meta-Ctrl-A) 上编码。

对于仅由 ASCII 字符组成的字符串(例如您的 )11111001,这三个字符是等效的。

请注意,与zsh除 ksh/bash 之外的所有其他 shell 一样,数组索引从 1 开始,而不是 0。

答案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")

相关内容