CalorieMate to Programmer #うちこむ人にバランス栄養 msg19 をLinuxのコマンドでTranslateする
概要
『CalorieMate to Programmer #うちこむ人にバランス栄養』というプロモーションがありました。 www.otsuka.co.jp
その中には色々なプログラム言語でのメッセージがあります。
msg19のメッセージが、ちょっと変わっていてバイナリーコードです。
最初はプログラムコードかな?と思ったのですが、トップページから言語メッセージを表示すると画面下の「Translate」が出てきます。
その「Translate」を押下すると、BALANCED FOR HUMAN.と出ます。
バイナリーコードの正体は文字コードでした。
でも、エンジニアなので自分で作ったコードで、バイナリーコードをTranslateしたいですよね!!
手順
※mac OSまたはWindows Subsystem for Linuxで動かすことを想定してます。
CUIモードに入って、バイナリーコードを取得します。
cd messages
と打ってからcat msg19.md
と打てばデータが取れます。
以下のようなデータが取れます。
01000010 01000001 01001100 01000001 01001110 01000011 01000101 01000100 00100000 01000110 01001111 01010010 00100000 01001000 01010101 01001101 01000001 01001110 00101110
これをローカルマシンにコピーしてファイル化します。
そして、以下のコマンドを打ちます。
cat msg19.md | for n in `xargs`;do echo "obase=16;ibase=2;$n" | bc | xxd -r -p ;done;echo
BALANCED FOR HUMAN.
と表示されました!
解説
やっていることは、こんな感じです。
- xargsで改行とスペースで区切られた標準入力を読み込み、スペースで区切られた1行の文字列に変換する。
- それをforに送り込むことで配列となり、ループするときに変数nに配列から抽出された文字列が入る。
- echoでbcコマンドに必要な文字列を追加する。
- bcコマンドで、2進数から16進数に変換する。
- xxdコマンドで16進数から文字列に変換する。
xargsでスペースで区切られた1行の文字列に変換しています。
forを使うことでスペース区切りは配列と認識され、nという変数にはループするごとに順番に配列から取得されていきます。
この仕組みを使うことで、パイプでつなげたbcコマンドやxxdコマンドを実行できるようにしています。
bcコマンドは色々なことができるのですが、今回はibase=2;
を指定して2進数から、obase=16;
を指定して16進数変換に使用しました。(順番は変えないでください)
xxdコマンドで文字列に変換すると書きましたが、このコマンドはデータを数値にダンプするもので、それをオプションの-rで逆変換しています。 (-pはプレーンフォーマットであることを明示するオプションです)
※xxdコマンドは16進数から逆変換できるのですが、2進数から逆変換ができないので、bcコマンドで2進数を16進数に変換します。
カロリーメイトのCUIで遊んだら、本物のCUIでも遊んでね💖
Perl版
cat msg19.md | for n in `xargs`;do echo "$n" | perl -e 'print pack("B*",<>)';done;echo
bcコマンドとxxdコマンドをPerlのpackに置き換えます。
バイナリーコードを文字に変換するのでpackを使います、2進数のバイナリーコードなので"B*"を指定します。
標準入力は<>で取得してます。
書いてて思いましたが、Perlのオプションを使うと、もう少し短くなりますし、Shellのforが不要になります。
やってみました、こんな感じです。
cat msg19.md | perl -ane 'foreach(@F){print pack("B*",$_)}END{print"\n"}'
-nでwhileモード、-aでオートスプリットモードで、@Fには配列が入っているので、それをforeachで取り出し$_をpackして表示するだけです。
Ruby版
cat msg19.md | ruby -ane '$F.each{|value|print [value].pack("B*")};END{puts}';
Perl版と発想は同じです。
Rubyは$Fに配列が入ります。
PHP版
cat msg19.md | php -R 'foreach(explode(" ",trim($argn))as$value){echo pack("H*",base_convert($value,2,16));}' -E 'echo"\n";'
PHP5でも動きます。
PHPはオートスプリットモードが無いので、その部分は実装しないといけないので、標準入力を$argnで受け取り、explodeを使って配列にしていきます。
packは2進数変換が無いので、代わりに16進数に変換するためbase_convertを使用します。
行頭のスペースが配列に入ってしまうので、trimします。
Vue.js版
こちらは、今までとは逆に文字列をバイナリーコードに変換します。
実際に動いているのは、こちらになります。
msg19.netlify.app
ソースはこちらです。
github.com
bootstrap5 とかも使ってます。
Python版
cat msg19.md | python -c 'import sys;import struct;[([(print(struct.pack("B",int(value,2)).decode(),end=""))for value in list])for list in[line.split()for line in sys.stdin]];print()'
Python3で動きます。
PythonはPHPと同じでオートスプリットモードが無いので、その部分は実装しないといけないので、事前にimport sysをしておいてから、標準入力をsys.stdinで受け取り、splitを使ってlistにしていきます、そのlistを更にforで回していきます。
文字列をintの第2引数で2進数を指定して数値化してからpackにかけます。
packは事前にimport structしてから実行します。
packの実行結果はバイナリーデータのままなので、decodeして文字列化します。
printは、そのままだと改行されてしまうのでend=""で改行を抑止します。
Python版は物凄くややこしくなっています。
CUIモード
おまけ CUIモードが楽しかったです。
www.otsuka.co.jp
暇があったら、やってみましょう!
当然ながらview-source:も確認済み pic.twitter.com/zQeDPj2ttN
— さっぴー川原🍶 (@sapi_kawahara) 2020年8月3日
view-sourceにも遊び心がありました。
Developer toolのconsoleにもメッセージがありました。
以下ネタバレなので、コマンド探しをしたい人は見ないでください。
なお、helpコマンドと、helpコマンで紹介されているコマンドは記載してません。
ツイッターのモーメントにまとめました。