Q1 GNU sedと同じ。
% echo abcdefghijklmn | ex /dev/stdin +'s/\(.\)\(.\)/\1\u\2/g|p|q!' aBcDeFgHiJkLmN % echo abcdefghijklmn | vim -es /dev/stdin +'s/../\u&/g|p|q!' AbCdEfGhIjKlMn
文字単位の移動も簡単にできるので、ブレース展開との合わせ技で。
% echo abcdefghijklmn | vim -es /dev/stdin +'norm l~'{,,,,,,} +'p|q!'
aBcDeFgHiJkLmN
% echo abcdefghijklmn | vim -es /dev/stdin +'norm ~l'{,,,,,,} +'p|q!'
AbCdEfGhIjKlMn
Q2 FizzBuzz
% vim -es +$'norm 33o\nFizz\n\e' +$'let @a="ABuzz\e5k"|norm 20@a' +'%s/^$/\=line(".")/|%p|q!'
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
<以下略>
normだとなぜかqでのマクロが保存できないので苦肉の策。直接レジスタに入れてる。
行って帰って間を埋める。生のESC等は扱い辛いので$''で表現。
Q3 3move7
% seq 1 10 | vim -es /dev/stdin +'3m7|%p|q!' 1 2 4 5 6 7 3 8 9 10
実にvim向きの問題。
Q4 aho.cc
% cat aho.cc | vim -es /dev/stdin +'/main/,/^}/m$|%p|q!' | g++ -xc++ -; ./a.out aho
これもmove一発。Q3と同じ。
Q5 偶奇入れ替え
% seq 10 | vim -es /dev/stdin +1 +'m+1|+1'{,,,,} +'%p|q!'
2
1
4
3
6
5
8
7
10
9
奇数行でm+1を実行すると現在行と次行が入れ替わるので、さらに次行に移動(+1)し、
ブレース展開で5回繰り返し。
Q6 階段状
% echo 1 | vim -es /dev/stdin +'for i in range(10)|p|s/./&&/|endfor|q!' 1 11 111 1111 11111 111111 1111111 11111111 111111111 1111111111
p|s/./&&/を10回繰り返し。ブレース展開技でもいけそうだが、
vimのわけのわからない制限により10個までしか指定できない。
% echo 1 | vim -es /dev/stdin +'p|s/./&&/'{1..10} +'q!'
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 22:32:42)
Too many "+command", "-c command" or "--cmd command" arguments
More info with: "vim -h"
Q7 縛り1 使うコマンドはseq、cp、vimだけ
% rm a*
% vim -es +'wq a'
% seq 10 | vim -es /dev/stdin +'g/^/exe "!cp a a" . getline(".")' +'q!'
% ls
a a1 a10 a2 a3 a4 a5 a6 a7 a8 a9
Q7 縛り2 ワンライナー中で数字を使わない
実はgetline(".")をline(".")に変更すれば行番号が使えるので、
なんでもいいので10行作ればいい。
% rm a*
% vim -es +'wq a|norm Yppppppppp' +'g/^/exe "!cp a a" . line(".")' +'q!'
% ls
a a1 a10 a2 a3 a4 a5 a6 a7 a8 a9
ついでにseq 10相当をvimで。
% vim -es +'norm Yppppppppp' +'%#|q!'
1
2
3
4
5
6
7
8
9
10
微妙に違うのでちょっとがんばってみた。
% vim -es +'norm Yppppppppp' +'%s/^/\=line(".")' +'%p|q!'
1
2
3
4
5
6
7
8
9
10
Q8 山
% echo 1 | vim -es /dev/stdin +'t.|s/./&&'{,,,} +'g/^/t5' +'%p|q!'
1
11
111
1111
11111
11111
1111
111
11
1
tはcopyの別名。cはchangeなのでcopyは短縮形でもcoと書かないといけないが、
1文字で書きたい人のためにtは用意されてるとか?
今回はリモート参戦。
sedのtがどーのこーのとあったので、Q6をtを使って解く。
bはgotoでtはsでの置き換えが成功したら飛ぶというだけなので、
まあ、そんな難しい話でもない。
sの成功フラグはtやTで飛ぶか次のサイクルへ移行したらOFFになる。
まずはbを使った場合。
% echo 1 | sed ':a;p;s/./&&/;/.\{10\}/!b a'
1
11
111
1111
11111
111111
1111111
11111111
111111111
1111111111
9回繰り返すだけだ。10回じゃないのはデフォルトの出力が最後にあるため。
1と限定できればs/^/1/と短く書けるが、
echo aとか任意の文字でもいいようにしている。
これを踏まえて、tを使うようにする。
sのパターンで10個以上になったらmatchしないようにしてやればいいだけ。
% echo 1 | sed -nr ':a;p;s/^(.){1,9}$/&\1/;t a'
1
11
111
1111
11111
111111
1111111
11111111
111111111
1111111111
\があると見辛いので-rを使った。
/^(.){1,9}$/とすることで1から9文字のときだけmatchする。
9回繰り返すという意味では例のブレース展開技も使える。
% echo 1 | sed -e'p;s/./&&/;#'{1..9}
1
11
111
1111
11111
111111
1111111
11111111
111111111
1111111111