Base
Base
RFC 4648에 따라 데이터를 인코딩/디코딩해 주는 모듈이에요. 흔히 쓰는 base 16, base 32, base 64 인코딩 방식을 구현해 두었죠. 데이터를 바이너리 문자열로 바꾸거나, 반대로 바이너리 문자열을 원래 데이터로 되돌릴 때 써요.
본문
이 모듈은 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 | :mixedencode_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: :whitespace와 padding: 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:padding—true면 출력을 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:padding—true면 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: :whitespace와 padding: 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: 바이너리 리터럴과 바이트 다루기