たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

第41回シェル芸勉強会に参加しました

参加しました

かんたんに感想を述べると、楽しかったです

午前

鳥海さんの文字コードシリーズ、第6回でした。今度こそ最終回だそうです。さみしい

資料はここ(Tweetへのリンク)です。

お話はUnicode結合文字についてでした。

部品の集合とすることで、あらゆる文字を表現できるようにしているんですが、単純な比較ができない・1文字の判定が難しいなどの問題があります

# 回文なのでもとのまま
echo おかしがすきすきすがしかお|rev
おかしがすきすきすがしかお

# uconv -x NFDでUnicode結合文字列へ分解できる。revすると濁点の位置がずれる
echo おかしがすきすきすがしかお|uconv -x NFD|rev
おかじかすきすきずかしかお

面白いですね。これらを正しく見るにはUnicodeの正規化(uconv -x NFC)や書記素クラスタ(正規表現\X)などを使っていけばいいみたいです

# grep -o . だとばらばらになる
$ echo -e た"\U3099" | grep -o .
た
゛

# Unicode正規化
$ echo -e た"\U3099" | uconv -x NFC | grep -o .
だ

# 書記素クラスタ
$ echo -e た"\U3099" | perl -C -lne "print for /\X/g"

他にもZWJや国旗絵文字シーケンス、ワタナベ難読化シェル芸で使った異体字セレクタなどが紹介されました。

特に国旗絵文字シーケンスは国旗難読化シェル芸の可能性を感じました。やるしかない

午後

「相当アレ」と告知がありましたが、sortのことだったようです。ふむ

問題と解答はここです

Q1

ファイルの2列目をキーにExcel順に並び替える問題

Excel順はA...Z,AA...ZZ,AAA...ZZZというやつですね。やってみます

$ cat excel | awk '{print $0, length($2)}'|sort -k3 -k2|awk '{print $1,$2}'

awk を使ってキーの長さを出力しておき、それらを使って sort コマンドで並び替えます。
-k[num] を指定すると [num] 列目をキーに並び替えしてくれます。並べて書くこともできます。
LINQ的に書くと .OrderBy(3列目のキー).ThenBy(2列目のキー) みたいな感じですね

Q2

干支の感じとその読みが書かれた eto_yomi ファイルの中身を干支順に並び替える問題。干支の順番は eto ファイルに書かれているので使ってもいいみたいです。やってみます

cat ShellGeiData/vol.41/eto_yomi <(grep -o . ShellGeiData/vol.41/eto) |awk 'NR<=12{x[$1]=$2}NR>12{print $1, x[$1]}'

やっていることは、まず eto_yomi の1行目をキーに awk連想配列にぶち込みます(12個です)。その後 eto の1文字をキーに連想配列を読み出して出力します。 sort は使ってませんごめんなさい

この問題でこのパターンを覚えてしまったので以降でも出てきます

Q3

第一フィールドの計算結果が小さい順にレコードを並べ替える問題。やってみます

cat ShellGeiData/vol.41/kim_calc|awk '{print "echo \"$(("$1"))\"",$0}'|bash|sort -n|awk '{print $2,$3}'

awk を使って echo $((第一フィールド)) 第一フィールド 第二フィールド という文字列を作ります。 これを bash に流し込んでやると第一フィールドの計算値がわかるので、それをキーに sort し出力を整えて終わりです

この問題では seds///e が話題になったのでそっちもやってみます

$ cat ShellGeiData/vol.41/kim_calc|sed 's/^.* /echo "$((&))" &/e'|sort -n|awk '{print $2,$3}'

コマンドの生成と実行が sed 内で完結するのでシンプルになりますね

Q4

Shift-JISで書かれたファイルを1) 文字列としてソート 2) 第一フィールドの数字が小さい順にソート する問題。出力もShift-JISで出すこと。

1)はまだいいですが、2)は数字が全角で書かれているので何か変換しないとダメそうですね。やってみます

1) nkf ShellGeiData/vol.41/sjis | sort | iconv -t sjis
2) nkf -Z ShellGeiData/vol.41/sjis |sort -n|uconv -x Halfwidth-Fullwidth|sed 's/ / /'|iconv -t sjis

まずは1) からです。とりあえず nkf でUTF8に変換します。文字列順にソートすればいいので普通に sort します。そのあと iconv でShift-JISにして終わりです。

この問題、僕もそうだったのですが一度UTF8に変換する解答が多かったです。しかし、並び替えるだけならその必要もなく…

1 別解) LANG=C sort ShellGeiData/vol.41/sjis

でいいわけですね。

次に2) です。今度は全角⇔半角の変換してやる必要がありそうです。 nkf-Z がどんなことをするのか、 nkf --help を見てみます。

Z[0-4] Default/0: Convert JISX0208 Alphabet to ASCII 1: Kankaku to one space 2: to two spaces 3: HTML Entity 4: JISX0208 Katakana to JISX0201 Katakana

$ echo "A1@"|nkf -Z0
A1@

デフォルトの -Z0 はJISX0208のアルファベットやらをASCIIにしてくれるみたいですね

これで第一フィールドが半角数字になったので、 sort -n でうまく並べ替えることができます。

次に uconv で半角にした数字を全角へ戻します。 -x Halfwidth-Fullwidth を指定するとその通り半角から全角へ変換してくれます。

最後に uconv に巻き込まれた半角スペースをもとに戻して終わりです

Q5

size というファイルにはデータのサイズがいくつか書かれていて、これをサイズ順に並べ替える問題。

この問題の厄介なところは 410MB とか 0.4GB とかが混在するところですね。やってみます

paste <(cat ShellGeiData/vol.41/size|sed 's/B//g;s/G/E9/g;s/M/E6/g;s/k/E3/g') ShellGeiData/vol.41/size|sort -g|awk '{print $2}'

paste の部分だけ実行するとどうなるか見てみます

$ paste <(cat ShellGeiData/vol.41/size|sed 's/B//g;s/G/E9/g;s/M/E6/g;s/k/E3/g')
2E9 2GB
1.2E9   1.2GB
40000E6 40000MB
1000000000E3    1000000000kB
0.4E9   0.4GB
410E6   410MB

sort に使うキーとして、SIを指数表記(E9とか)へ変換したものを追加します。ここで sort -g を使うと指数表記も解釈して並び替えてくれます。その後整形して終わりです

一応 sort-g がどんなことをしてくれるのか、sort --help を見てみます

-g, --general-numeric-sort compare according to general numerical value

general numerical value ってなんだよって話ですね。このstackoverflowの質問の回答にもありますが、-g は低速になるが指数表記を解釈でき、浮動小数点として並び替えてくれるようですね。なるほどこれはいいですね

Q6

sleep と組み込みコマンドのみを使って nums を並び替える問題

スリープソートと言うやつらしいですね。やってみます

while read l; do (sleep $l && echo $l)& done < ShellGeiData/vol.41/nums

while echo read は組み込みです。 これらを使って sleep 時間 && echo 時間 というコマンドをほぼ同時に起動し、スリープソートを行います

こういう問題は難読化してやればごまかせるかもしれないですね

$ : "$(sleep --version)" && ${_:0:1}${_:12:2}${_:16:1} ./ShellGeiData/vol.41/nums
0.34
0.9
2.3
5.4
6

そんなに高度なことはしてないので読んでみるといいかもしれません

Q7

ローマ数字をソートする問題

paste <(numconv < ShellGeiData/vol.41/roman) ShellGeiData/vol.41/roman|sort -k1n|awk '{print $2}'

時間中に numconv というコマンドを知ったのでそれでやりました。すんごいですよこのコマンド

ちなみにOCaml製のCLIツールにromanってやつもあります。ggって見つけたのはこっちだったんですが、環境が入ってなかった

github.com

Q8

文字列を並び替える問題。ただし「か」より「が」が前で「き」より「ぎ」が前になるようにすること、ひらがなを使わないこと

午前中にやったことを使えばできそうですね

cat ShellGeiData/vol.41/gagigugego|uconv -x NFD|sort|uconv -x NFC

最初に提出したのは uconv -x NFC 無し版だったんですが、これはどうやらお行儀が悪いらしいです。確かによくなさそうですね。

ところでこの解答どうやら想定されていたみたいなんですが、環境によってはダメ。ということでした。難しいですね

ひらがなを使ったバージョンも作ってみました。Q2で使ったパターンと同じですが

echo がかぎきぐくげけごこ|grep -o .|cat <(sed 's/^./& &/g' <ShellGeiData/vol.41/gagigugego) -|awk 'NR<=10{x[$1]=x[$1]" "$2}NR>10{print x[$1]}'|xargs -n1

LT

今回もLTさせていただきました!聞いてくださった皆様ありがとうございました!テーマは「CLIからドット絵画像を出力」です

www.slideshare.net

https://github.com/xztaityozx/t2p

入力文字列からテーブルを使って色を決定、ドット絵へ変換します。半日クオリティです

終わりに

今回もとても楽しかったです!運営の皆様ありがとうございました!あと素材にしてすいませんでした