LoginSignup
14
2

More than 1 year has passed since last update.

さまざまな場面でIDを生成したくなることがあると思います。Qiitaの記事のURLも何らかのアルゴリズムでIDが生成されています。例、https://qiita.com/mnishiguchi/items/90380b61df4e41966556

ID生成のやり方と言っても要求事項によるので銀の弾丸はないと思います。

いろんなパターンを知っておくといざという時の判断材料になると思い、お手本があればメモするようにしています。

日付・時間

  • 単純なデータなので処理が高速
  • 厳密にいうとIDではないがこれで用が足りることもある

System.monotonic_time/1

  • 不特定の時点から始まる単調に増加する時間
  • 例、50549
System.monotonic_time(:millisecond)

System.os_time/1

System.os_time(:millisecond)

DateTime.to_unix/2

  • System.os_time(:second)と同じっぽい
  • 例、1668560794
DateTime.utc_now |> DateTime.to_unix

DateTime.to_iso8601/3

  • 例、"2022-11-16T01:06:51.322281Z"
DateTime.utc_now |> DateTime.to_iso8601

文字列のMD5ハッシュ値を計算しBase16にエンコード

  • 不可解な値に見せたいときに最適
  • 例、"E3FABC6EBCAA52300311DF162AE35BF1"
IEx
iex> "闘魂" |> :erlang.md5() |> Base.encode16()
"E3FABC6EBCAA52300311DF162AE35BF1"
IEx
iex> "闘魂" |> :erlang.md5() |> Base.encode16(case: :lower)
"e3fabc6ebcaa52300311df162ae35bf1"

:crypto.strong_rand_bytes/1

Livebookの例

# random_short_id
# 例、"kmrfwizk"
:crypto.strong_rand_bytes(5) |> Base.encode32(case: :lower)
# random_id
# 例、"3nbztnwq5wi6fhmerpgxbwbryo6b27os"
:crypto.strong_rand_bytes(20) |> Base.encode32(case: :lower)
# random_cookie
# 例、"5QpirBHr0XWdCCdudCsvZ-nuNLuiRAkF0wR_DdKm03plKbwEvvSG"
:crypto.strong_rand_bytes(39) |> Base.url_encode64()

文字列の長さを一定にしたい場合は、Kernel.binary_slice/2 (または Kernel.binary_part/3)が便利そうです。

:crypto.strong_rand_bytes(20) |> Base.url_encode64 |> binary_part(0, 20)
:crypto.strong_rand_bytes(20) |> Base.url_encode64 |> binary_slice(0..19)

Mix.Tasks.Phx.Gen.Secretの例

  • ランダム文字列の長さの最小値が32となっている
  • Kernel.binary_part/3を用いて結果をユーザー指定の長さに調整している
defmodule MySecret do
  def random_string(length) when length > 31 do
    :crypto.strong_rand_bytes(length)
    |> Base.encode64(padding: false)
    |> binary_part(0, length)
  end

  def random_string(_) do
    Mix.raise "The secret should be at least 32 characters long"
  end
end

MySecret.random_string(32)

UUID

  • 同一の文字列が2つ生成される可能性が高い大規模なコンテキストに最適
  • zyro/elixir-uuidパッケージをインストールする必要がある
  • 例、69134ff3-4bfe-3945-a04d-7e694c77121c

UUIDのバージョン

  • バージョン1 - MAC address + datetime into 128 bits
  • バージョン3 - MD5 hash into 128 bits
  • バージョン4 - random data into 128 bits
  • バージョン5 - SHA1 hash into 128 bits

迷ったらとりあえずバージョン3を選択すると無難そう。

zyro/elixir-uuidパッケージをインストールします。

IEx
iex> Mix.install [{:elixir_uuid, "~> 1.2.0"}]

名前空間を指定する必要がある。迷ったら:dnsにしておけばOK。

IEx
iex> UUID.uuid3(:dns, "mnishiguhchi.com")
"0aaa56b1-0810-3a73-aa3d-63a2f6b3d28d"

有効なUUIDを名前空間として使用することも可能。

IEx
iex> UUID.uuid3("0aaa56b1-0810-3a73-aa3d-63a2f6b3d28d", "闘魂")
"16c19ad5-e030-3829-9599-26961d8ef802"

ご参考までに

14
2
1

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
14
2