LoginSignup
4
0

More than 3 years have passed since last update.

Elixirの文字で遊ぶ

Last updated at Posted at 2019-12-25

Advent Calnder.png

雰囲気でエンジニアやっています。

トリなんですが昨日熱を出して最高なイブを過ごし、更にクリスマスであることすら忘れていたので、今サンタさんもびっくりなくらい大慌てなわけです。
ってなわけで何番煎じかわからないけど、Elixirの不思議(?)な文字の世界で遊びます。

彼女(妄想)からL○NE来た

77 101 114 114 121 67 104 114 105 115 116 109 97 115

Elixirって時点で勘のいい人はすぐに何が書いてあるかわかりますね。
こんなL○NEを送ってくれるバイナリアンな彼女がいたら嬉しいですね。

わからなかったらElixirをインスコしてReplを起動して、可愛い彼女のために何が書いてあるか読み解きましょう。

$ iex
Erlang/OTP 22 [erts-10.6.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> <<77, 101, 114, 114, 121, 67, 104, 114, 105, 115, 116, 109, 97, 115>>
"MerryChristmas"

素敵なメッセージ!

<<>> でバイナリの世界へ簡単にダイブ

大体どのプログラミング言語でもある、Fileを読んだりするやつを見てみます。

File.read("hoge.wav")
# {:ok,
# <<82, 73, 70, 70, 252, 94, 66, 2, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0,
#   0, 1, 0, 2, 0, 68, 172, 0, 0, 16, 177, 2, 0, 4, 0, 16, 0, 100, 97, 116, 97,
#   236, 93, 66, 2, 0, 0, 0, 0, ...>>}

ここでWaveファイルをせっかく読んだのでちらっとヘッダを覗いてみます。Waveファイルの構造については別途参照ください。

defmodule Wave do
  def parse(file) do
    File.read(file)
    |> header()
  end

  def header({:error, _}), do: {:error, "読み込み失敗"}
  def header({:ok, body}) do
    <<riff :: binary-size(4), size :: unsigned-size(32), wave_header :: binary-size(4), fmt_chunk :: binary-size(4), rest :: binary>> = body
    IO.inspect riff
    IO.inspect size
    IO.inspect wave_header
    IO.inspect fmt_chunk
    IO.inspect rest
  end
end

適当なWaveファイルを読ませてみます。

$ iex -S mix
iex(1)> Wave.parse("hoge.wav")
"RIFF"
4234035714
"WAVE"
"fmt "
<<16, 0, 0, 0, 1, 0, 2, 0, 68, 172, 0, 0, 16, 177, 2, 0, 4, 0, 16, 0, 100, 97,
  116, 97, 236, 93, 66, 2, 0, 0, 0, 0, 0, 0, 255, 255, 1, 0, 2, 0, 254, 255,
  253, 255, 3, 0, 4, 0, 252, 255, ...>>

パターンマッチ最高。

文字もバイナリ

なんです。

"a" <> "b" # "ab"
"a" <> <<0>> # <<97, 0>>
match? "a", <<97>> # true

結局その数字は何かってASCIIなんですね。
まぁこの辺はElixirのチュートリアルでも書いてあることですね。

もっと分解してみる

先程の彼女からのメッセージの頭文字 "M" でちょっと深堀りします。
"M" <> <<0>><<77, 0>> なので <<77>> == "M" ですね(?Mだけでも調べられます)。
77 は2進数で 1001101 ですね。これをElixir的に書くと

<<0::1, 1::1, 0::1, 0::1, 1::1, 1::1, 0::1, 1::1>>

ということは

$ iex -S mix
iex(1)> <<0::1, 1::1, 0::1, 0::1, 1::1, 1::1, 0::1, 1::1>>
"M"
iex(2)> match? "M", <<0::1, 1::1, 0::1, 0::1, 1::1, 1::1, 0::1, 1::1>>
true

これだけ見るとわけがわかりませんね。

まとめ

普段はあまり触れない0/1の世界へ、意外と手軽に入っていける面白さがElixirにはあるなぁと思います。
フワッと理解していたbitとかの単位についてがクリアになるなぁと。
あとElixirのパターンマッチのおかげでこの手のコードは短く書けると思います。
前前前職ではElixirを使って結構バイナリいじって楽しんでました。そのときに作ったライブラリがいくつか公開していたはず……

意外と話が広がらなくて困りましたが、とりあえずメリークリスマス。
みなさんアドベントカレンダお疲れさまでした。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0