Base

Base

RFC 4648에 따라 데이터를 인코딩/디코딩해 주는 모듈이에요. 흔히 쓰는 base 16, base 32, base 64 인코딩 방식을 구현해 두었죠. 데이터를 바이너리 문자열로 바꾸거나, 반대로 바이너리 문자열을 원래 데이터로 되돌릴 때 써요.

출처: Base (Elixir v1.20.4)

본문

이 모듈은 RFC 4648에서 정의한 base 16, base 32, base 64 인코딩 방식을 다룬답니다. 각 인코딩은 고유한 알파벳(문자 집합)을 쓰는데, 그 알파벳은 아래 표와 같아요.

Base 16 알파벳

인코딩 인코딩 인코딩 인코딩
0 0 4 4 8 8 12 C
1 1 5 5 9 9 13 D
2 2 6 6 10 A 14 E
3 3 7 7 11 B 15 F

Base 32 알파벳

인코딩 인코딩 인코딩 인코딩
0 A 9 J 18 S 27 3
1 B 10 K 19 T 28 4
2 C 11 L 20 U 29 5
3 D 12 M 21 V 30 6
4 E 13 N 22 W 31 7
5 F 14 O 23 X
6 G 15 P 24 Y (패딩) =
7 H 16 Q 25 Z
8 I 17 R 26 2

Base 32 (확장 16진수) 알파벳

인코딩 인코딩 인코딩 인코딩
0 0 9 9 18 I 27 R
1 1 10 A 19 J 28 S
2 2 11 B 20 K 29 T
3 3 12 C 21 L 30 U
4 4 13 D 22 M 31 V
5 5 14 E 23 N
6 6 15 F 24 O (패딩) =
7 7 16 G 25 P
8 8 17 H 26 Q

Base 64 알파벳

인코딩 인코딩 인코딩 인코딩
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (패딩) =
15 P 32 g 49 x
16 Q 33 h 50 y

Base 64 (URL·파일명 안전) 알파벳

인코딩 인코딩 인코딩 인코딩
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 -
12 M 29 d 46 u 63 _
13 N 30 e 47 v
14 O 31 f 48 w (패딩) =
15 P 32 g 49 x
16 Q 33 h 50 y

타입

  • decode_case() : @type decode_case() :: :upper | :lower | :mixed
  • encode_case() : @type encode_case() :: :upper | :lower

함수

decode16(string, opts \ [])

[@spec decode16(binary(), [{:case, decode_case()}]) :: {:ok, binary()} | :error]

base 16으로 인코딩된 문자열을 바이너리 문자열로 디코딩해요.

옵션은 :case 하나예요. 디코딩할 때 허용할 문자 대소문자를 지정하죠.

  • :upper — 대문자만 허용 (기본값)
  • :lower — 소문자만 허용
  • :mixed — 대소문자 혼용 허용
iex> Base.decode16("666F6F626172")
{:ok, "foobar"}
iex> Base.decode16("666f6f626172", case: :lower)
{:ok, "foobar"}
iex> Base.decode16("666f6F626172", case: :mixed)
{:ok, "foobar"}

decode16!(string, opts \ [])

[@spec decode16!(binary(), [{:case, decode_case()}]) :: binary()]

base 16으로 인코딩된 문자열을 바이너리 문자열로 디코딩해요. 옵션은 decode16/2와 동일해요. 패딩이 올바르지 않거나 알파벳에 없는 문자가 들어 있으면 ArgumentError 예외를 던져요.

iex> Base.decode16!("666F6F626172")
"foobar"
iex> Base.decode16!("666f6f626172", case: :lower)
"foobar"
iex> Base.decode16!("666f6F626172", case: :mixed)
"foobar"

decode32(string, opts \ [])

[@spec decode32(binary(), case: decode_case(), padding: boolean()) :: {:ok, binary()} | :error]

base 32로 인코딩된 문자열을 바이너리 문자열로 디코딩해요.

옵션은 :case:padding 두 가지예요.

  • :case 의 값은 decode16/2와 같아요. (:upper 기본, :lower, :mixed)
  • :padding 의 값은:
    • true — 입력 문자열이 8의 배수로 패딩돼 있어야 함 (기본값)
    • false — 입력 문자열의 패딩을 무시함
iex> Base.decode32("MZXW6YTBOI======")
{:ok, "foobar"}
iex> Base.decode32("mzxw6ytboi======", case: :lower)
{:ok, "foobar"}
iex> Base.decode32("mzXW6ytBOi======", case: :mixed)
{:ok, "foobar"}
iex> Base.decode32("MZXW6YTBOI", padding: false)
{:ok, "foobar"}

decode32!(string, opts \ [])

[@spec decode32!(binary(), case: decode_case(), padding: boolean()) :: binary()]

base 32로 인코딩된 문자열을 바이너리 문자열로 디코딩해요. 패딩이 올바르지 않거나 알파벳에 없는 문자가 있으면 ArgumentError 예외를 던져요. 옵션은 decode32/2와 동일해요.

iex> Base.decode32!("MZXW6YTBOI======")
"foobar"
iex> Base.decode32!("mzxw6ytboi======", case: :lower)
"foobar"
iex> Base.decode32!("mzXW6ytBOi======", case: :mixed)
"foobar"
iex> Base.decode32!("MZXW6YTBOI", padding: false)
"foobar"

decode64(string, opts \ [])

[@spec decode64(binary(), ignore: :whitespace, padding: boolean()) :: {:ok, binary()} | :error]

base 64로 인코딩된 문자열을 바이너리 문자열로 디코딩해요. ignore: :whitespace 옵션을 주면 입력 문자열의 모든 공백 문자를 무시하고, padding: false 옵션을 주면 입력 문자열의 패딩을 무시해요.

iex> Base.decode64("Zm9vYmFy")
{:ok, "foobar"}
iex> Base.decode64("Zm9vYmFy\n", ignore: :whitespace)
{:ok, "foobar"}
iex> Base.decode64("Zm9vYg==")
{:ok, "foob"}
iex> Base.decode64("Zm9vYg", padding: false)
{:ok, "foob"}

decode64!(string, opts \ [])

[@spec decode64!(binary(), ignore: :whitespace, padding: boolean()) :: binary()]

base 64로 인코딩된 문자열을 바이너리 문자열로 디코딩해요. ignore: :whitespacepadding: false 옵션을 받고, 패딩이 올바르지 않거나 알파벳에 없는 문자가 있으면 ArgumentError 예외를 던져요.

iex> Base.decode64!("Zm9vYmFy")
"foobar"
iex> Base.decode64!("Zm9vYmFy\n", ignore: :whitespace)
"foobar"
iex> Base.decode64!("Zm9vYg==")
"foob"
iex> Base.decode64!("Zm9vYg", padding: false)
"foob"

encode16(data, opts \ [])

[@spec encode16(binary(), [{:case, encode_case()}]) :: binary()]

바이너리 문자열을 base 16으로 인코딩된 문자열로 바꿔요.

:case 옵션으로 인코딩에 쓸 대소문자를 정해요.

  • :upper — 대문자 사용 (기본값)
  • :lower — 소문자 사용
iex> Base.encode16("foobar")
"666F6F626172"
iex> Base.encode16("foobar", case: :lower)
"666f6f626172"

encode32(data, opts \ [])

[@spec encode32(binary(), case: encode_case(), padding: boolean()) :: binary()]

바이너리 문자열을 base 32로 인코딩된 문자열로 바꿔요.

  • :case:upper(기본), :lower
  • :paddingtrue면 출력을 8의 배수로 패딩(기본), false면 패딩 생략
iex> Base.encode32("foobar")
"MZXW6YTBOI======"
iex> Base.encode32("foobar", case: :lower)
"mzxw6ytboi======"
iex> Base.encode32("foobar", padding: false)
"MZXW6YTBOI"

encode64(data, opts \ [])

[@spec encode64(binary(), [{:padding, boolean()}]) :: binary()]

바이너리 문자열을 base 64로 인코딩된 문자열로 바꿔요. padding: false 옵션을 주면 출력 문자열의 패딩을 생략해요.

iex> Base.encode64("foobar")
"Zm9vYmFy"
iex> Base.encode64("foob")
"Zm9vYg=="
iex> Base.encode64("foob", padding: false)
"Zm9vYg"

hex_decode32(string, opts \ [])

[@spec hex_decode32(binary(), case: decode_case(), padding: boolean()) :: {:ok, binary()} | :error]

확장 16진수 알파벳으로 base 32 인코딩된 문자열을 바이너리 문자열로 디코딩해요. 옵션은 decode32/2와 같아요.

iex> Base.hex_decode32("CPNMUOJ1E8======")
{:ok, "foobar"}
iex> Base.hex_decode32("cpnmuoj1e8======", case: :lower)
{:ok, "foobar"}
iex> Base.hex_decode32("cpnMuOJ1E8======", case: :mixed)
{:ok, "foobar"}
iex> Base.hex_decode32("CPNMUOJ1E8", padding: false)
{:ok, "foobar"}

hex_decode32!(string, opts \ [])

[@spec hex_decode32!(binary(), case: decode_case(), padding: boolean()) :: binary()]

확장 16진수 알파벳으로 base 32 인코딩된 문자열을 바이너리 문자열로 디코딩해요. 패딩이 올바르지 않거나 알파벳에 없는 문자가 있으면 ArgumentError 예외를 던져요.

iex> Base.hex_decode32!("CPNMUOJ1E8======")
"foobar"
iex> Base.hex_decode32!("cpnmuoj1e8======", case: :lower)
"foobar"
iex> Base.hex_decode32!("cpnMuOJ1E8======", case: :mixed)
"foobar"
iex> Base.hex_decode32!("CPNMUOJ1E8", padding: false)
"foobar"

hex_encode32(data, opts \ [])

[@spec hex_encode32(binary(), case: encode_case(), padding: boolean()) :: binary()]

바이너리 문자열을 확장 16진수 알파벳으로 base 32 인코딩된 문자열로 바꿔요.

  • :case:upper(기본), :lower
  • :paddingtrue면 8의 배수로 패딩(기본), false면 생략
iex> Base.hex_encode32("foobar")
"CPNMUOJ1E8======"
iex> Base.hex_encode32("foobar", case: :lower)
"cpnmuoj1e8======"
iex> Base.hex_encode32("foobar", padding: false)
"CPNMUOJ1E8"

hex_valid32?(string, opts \ []) (1.19.0부터)

[@spec hex_valid32?(binary(), case: decode_case(), padding: boolean()) :: boolean()]

확장 16진수 알파벳으로 base 32 인코딩된 문자열이 유효한지 확인해요.

언제 쓰면 좋을까요. 실제로 디코딩된 출력 문자열이 필요 없이, 해당 문자열이 (확장 16진수) base 32 데이터로 유효한지만 검증하고 싶을 때 써요. hex_decode32/2로 디코딩해서 결과가 {:ok, ...}인지 확인하고 바이너리를 버리는 방식보다 이 함수가 더 빠르고 메모리도 절약돼요. 옵션은 hex_decode32/2와 같아요.

iex> Base.hex_valid32?("CPNMUOJ1E8======")
true
iex> Base.hex_valid32?("cpnmuoj1e8======", case: :lower)
true
iex> Base.hex_valid32?("zzz", padding: false)
false

url_decode64(string, opts \ [])

[@spec url_decode64(binary(), ignore: :whitespace, padding: boolean()) :: {:ok, binary()} | :error]

URL·파일명 안전 알파벳으로 base 64 인코딩된 문자열을 바이너리 문자열로 디코딩해요. ignore: :whitespacepadding: false 옵션을 받아요.

iex> Base.url_decode64("_3_-_A==")
{:ok, <<255, 127, 254, 252>>}
iex> Base.url_decode64("_3_-_A==\n", ignore: :whitespace)
{:ok, <<255, 127, 254, 252>>}
iex> Base.url_decode64("_3_-_A", padding: false)
{:ok, <<255, 127, 254, 252>>}

url_decode64!(string, opts \ [])

[@spec url_decode64!(binary(), ignore: :whitespace, padding: boolean()) :: binary()]

URL·파일명 안전 알파벳으로 base 64 인코딩된 문자열을 바이너리 문자열로 디코딩해요. 패딩이 올바르지 않거나 알파벳에 없는 문자가 있으면 ArgumentError 예외를 던져요.

iex> Base.url_decode64!("_3_-_A==")
<<255, 127, 254, 252>>
iex> Base.url_decode64!("_3_-_A==\n", ignore: :whitespace)
<<255, 127, 254, 252>>
iex> Base.url_decode64!("_3_-_A", padding: false)
<<255, 127, 254, 252>>

url_encode64(data, opts \ [])

[@spec url_encode64(binary(), [{:padding, boolean()}]) :: binary()]

바이너리 문자열을 URL·파일명 안전 알파벳으로 base 64 인코딩된 문자열로 바꿔요. padding: false 옵션을 주면 출력 패딩을 생략해요.

iex> Base.url_encode64(<<255, 127, 254, 252>>)
"_3_-_A=="
iex> Base.url_encode64(<<255, 127, 254, 252>>, padding: false)
"_3_-_A"

url_valid64?(string, opts \ []) (1.19.0부터)

[@spec url_valid64?(binary(), ignore: :whitespace, padding: boolean()) :: boolean()]

URL·파일명 안전 알파벳으로 base 64 인코딩된 문자열이 유효한지 검증해요. 언제 쓰면 좋을까요. 디코딩 출력 없이 문자열이 유효한 (URL 안전) base 64 데이터인지만 확인하고 싶을 때 써요. url_decode64/2 결과를 {:ok, ...}인지 확인하고 바이너리를 버리는 방식보다 빠르고 메모리도 아껴요. 옵션은 url_decode64/2와 같아요.

iex> Base.url_valid64?("_3_-_A==")
true
iex> Base.url_valid64?("_3_-_A==\n", ignore: :whitespace)
true
iex> Base.url_valid64?("_3_-_A", padding: false)
true

valid16?(string, opts \ []) (1.19.0부터)

[@spec valid16?(binary(), [{:case, decode_case()}]) :: boolean()]

문자열이 유효한 base 16 인코딩 문자열인지 확인해요. 언제 쓰면 좋을까요. 디코딩 출력 없이 유효한 base 16 데이터인지만 검증하고 싶을 때 써요. decode16/2를 쓰고 결과를 확인하는 방식보다 빠르고 메모리도 절약돼요. 옵션은 decode16/2와 같아요.

iex> Base.valid16?("666F6F626172")
true
iex> Base.valid16?("666f6f626172", case: :lower)
true
iex> Base.valid16?("666f6F626172", case: :mixed)
true
iex> Base.valid16?("ff", case: :upper)
false

valid32?(string, opts \ []) (1.19.0부터)

[@spec valid32?(binary(), case: decode_case(), padding: boolean()) :: boolean()]

문자열이 유효한 base 32 인코딩 문자열인지 확인해요. 언제 쓰면 좋을까요. 디코딩 출력 없이 유효한 base 32 데이터인지만 검증하고 싶을 때 써요. 옵션은 decode32/2와 같아요.

iex> Base.valid32?("MZXW6YTBOI======")
true
iex> Base.valid32?("mzxw6ytboi======", case: :lower)
true
iex> Base.valid32?("zzz")
false

valid64?(string, opts \ []) (1.19.0부터)

[@spec valid64?(binary(), ignore: :whitespace, padding: boolean()) :: boolean()]

문자열이 유효한 base 64 인코딩 문자열인지 검증해요. 언제 쓰면 좋을까요. 디코딩 출력 없이 유효한 base 64 데이터인지만 확인하고 싶을 때 써요. 옵션은 decode64/2와 같아요.

iex> Base.valid64?("Zm9vYmFy")
true
iex> Base.valid64?("Zm9vYmFy\n", ignore: :whitespace)
true
iex> Base.valid64?("Zm9vYg==")
true

더 알아보기

  • Base.DecodeError: 디코딩 실패 시 예외
  • RFC 4648: base 16/32/64 인코딩의 표준 정의
  • Binary: 바이너리 리터럴과 바이트 다루기