読者です 読者をやめる 読者になる 読者になる

hkoba blog

プログラマーです。プログラミング言語ミーハーです。よろしくどうぞ(能代口調)

zsh 実験メモ:文字列変数の中から空白文字の位置を探したい時…

ふと迷ったのでメモ。ツッコミ希望です。

foo='key foo   bar
  baz...'

のような文字列変数が有るとして、これを key

"foo   bar
  baz..."

の2つに分割したい。

要するに perlsplit " ", $foo, 2 がしたい。

一旦配列変数に展開してから、2つ目以後を取り出して join し直す、だと、途中に複数のスペースや改行があっても 一文字にされてしまうので、いつでも使えるとは限らないなあと。

ary=($=foo)
print $ary[2,-1]

文字列の中から、特定の文字の位置を探すのは、 subscript の (r) や (i) フラグを使えばいける、 けど、スペースを subscript に書くとパースエラーになる。 \" " だとマッチしないし。

% foo='key foo   bar
  baz...'
% print $#foo
22
% print $foo[(i) ]
zsh: invalid subscript
% print $foo[(i)\ ]
23
% print $foo[(i)" "]
23
% print $foo[(i)' ']
23
% 

一時変数を作ってそこにスペース文字を入れれば行ける、けど、凄く負けた感が有る。

% k=' ';print $foo[(i)$k]
4

自分が思いついた解決策

${:-文字列式} を使う。ベストかどうか、分かりませんが。

% print $foo[(i)${:- }]
4
% print $foo[(r)${:- },-1]
 foo   bar
  baz...
% pos=$foo[(i)${:- }]
% print key=$foo[1,pos-1] value=$foo[pos+1,-1]
key=key value=foo   bar
  baz...
%
% print key=${(qq)foo[1,pos-1]} value=${(qq)foo[pos+1,-1]}
key='key' value='foo   bar
  baz...'
%

(key 側に off by one が有ったので訂正)

追記:上記を位置パラメータに使うには ${...} が必要…

% set -- --define 'dist .fc22.hk1'
% print $2[(i)${:- }]
zsh: no matches found: dist .fc22.hk1[(i) ]
% print ${2[(i)${:- }]}
5
% typeset -A defines
% p=${2[(i)${:- }]}
% defines[${2[1,p-1]}]=${2[p+1,-1]}
% print ${(kvqq)defines}
'dist' '.fc22.hk1'
%