6 바이너리, 문자열, 문자 리스트 - Binaries, strings and char lists

"기본 타입"에서 문자열에 대해 배웠고 타입체크를 위해 is_binary/1 을 사용했습니다:

In "Basic types", we learned about strings and used the is_binary/1 function for checks:

iex> string = "hello"
"hello"
iex> is_binary string
true

이 장에서는 바이너리가 무엇인지, 문자열과는 어떤 관계인지, '이렇게' 작은따옴표로 묶인 값은 Elixir 에서 어떤 의미를 가지는지에 대해 살펴볼 것입니다.

In this chapter, we will understand what binaries are, how they associate with strings, and what a single-quoted value, 'like this', means in Elixir.

6.1 UTF-8 와 Unicode - UTF-8 and Unicode

문자열은 UTF-8로 인코딩 된 바이너리입니다. 그것이 실제로 무슨 뜻인지 이해하기 위해서 바이트 및 코드 포인트의 차이를 모르면 안됩니다.

A string is a UTF-8 encoded binary. In order to understand exactly what we mean by that, we need to understand the difference between bytes and code points.

유니 코드 표준은 우리가 알고있는 많은 문자에 코드 포인트를 할당해 두었습니다. 예를들어 문자 a97 이라는 코드 포인트를 가지고 있고, 캐릭터 ł322 코드 포인트를 가지고 있습니다. 디스크에 문자열 "hełło"를 쓸 때 코드 포인트를 바이트로 변환해야 합니다. 만약 하나의 코드 포인트를 1 바이트로 표현한다면 "hełło" 라고 쓸 수 없습니다. 왜냐하면 ł 코드 포인트는 322 이며, 1 바이트는 0 에서 255 까지 밖에 표현할 수 없기 때문입니다. 그러나 화면에서는 "hełło" 를 읽을 수 있지요. 그것은 신비의 기술 로 표현되어 있기 때문입니다. 바로 인코딩되어 있기 때문입니다.

The Unicode standard assigns code points to many of the characters we know. For example, the letter a has code point 97 while the letter ł has code point 322. When writing the string "hełło" to disk, we need to convert this code point to bytes. If we adopted a rule that said one byte represents one code point, we wouldn't be able to write "hełło", because it uses the code point 322 for ł, and one byte can only represent a number from 0 to 255. But of course, given you can actually read "hełło" on your screen, it must be represented somehow. That's where encodings come in.

바이트에서 코드 포인트를 표현하는 경우 어떻게 해서든 인코딩을 해야 합니다. Elixir는 기본 인코딩으로 UTF-8 인코딩을 선택했습니다. 문자열은 UTF-8로 인코딩 된 바이너리라고 말할 때 의미하는 바는 문자열은 코드 포인트를 규칙에 따라 표현한 바이트의 모임이며, 그 규칙은 UTF-8 로 인코딩 된다는 것입니다.

When representing code points in bytes, we need to encode them somehow. Elixir chose the UTF-8 encoding as its main and default encoding. When we say a string is a UTF-8 encoded binary, we mean a string is a bunch of bytes organized in a way to represent certain code points, as specified by the UTF-8 encoding.

코드 포인트가 322 에 할당 되어있는 ł 경우 표현하려면 1 바이트보다 많은 바이트가 필요합니다. 때문에 문자열을 byte_size/1 로 계산했을 때와 String.length/1 로 계산했을 때의 차이가 있습니다:

Since we have code points like ł assigned to the number 322, we actually need more than one byte to represent it. That's why we see a difference when we calculate the byte_size/1 of a string compared to its String.length/1:

iex> string = "hełło"
"hełło"
iex> byte_size string
7
iex> String.length string
5

UTF-8은 h , eo 를 표현하려면 1 바이트만 들지만 ł 을 표현하기 위해 2 바이트 필요합니다. Elixir는 ? 을 사용하면 코드 포인트 값을 얻을 수 있습니다:

UTF-8 requires one byte to represent the code points h, e and o, but two bytes to represent ł. In Elixir, you can get a code point's value by using ?:

iex> ?a
97
iex> 
322

String 모듈의 함수를 사용하면 코드 포인트마다 문자를 나눌 수 있습니다:

You can also use the functions in the String module to split a string in its code points:

iex> String.codepoints("hełło")
["h", "e", "ł", "ł", "o"]

앞으로 문자열을 다루기 위해 Elixir가 훌륭한 지원을 한다는 것을 알게될 것입니다. 유니 코드 문자 작업도 많이 지원합니다. 실제로 Elixir는 "The string type is broken" 기사에 언급된 모든 테스트를 통과합니다.

You will see that Elixir has excellent support for working with strings. It also supports many of the Unicode operations. In fact, Elixir passes all the tests showcased in the article "The string type is broken".

여하튼 문자열은 스토리의 일부에 지나지 않습니다. 문자열은 바이너리이며, 우리는 (문자열) 함수 is_binary/1 을 사용했습니다, Elixir는 문자열에 힘을 실어 주는 근본적인 타입을 가지고 있습니다. 자 이제 바이너리 대해 살펴봅시다!

However, strings are just part of the story. If a string is a binary, and we have used the is_binary/1 function, Elixir must have an underlying type empowering strings. And it does. Let's talk about binaries!

6.2 바이너리(와 비트문자열) - Binaries (and bitstrings)

Elxir 에서 <<>>로 바이너리를 정의할 수 있습니다:

In Elixir, you can define a binary using <<>>:

iex> <<0, 1, 2, 3>>
<<0, 1, 2, 3>>
iex> byte_size <<0, 1, 2, 3>>
4

바이너리는 단순한 바이트들의 연속입니다. 물론 이러한 바이트들은 어떤 방식으로든 구성될 수 있습니다. 말이 되지 않는 문장도 가능합니다.

A binary is just a sequence of bytes. Of course, those bytes can be organized in any way, even in a sequence that does not make them a valid string:

iex> String.valid?(<<239, 191, 191>>)
false

문자열 연결 작업은 사실 바이너리의 결합 입니다:

The string concatenation operation is actually a binary concatenation operator:

iex> <<0, 1>> <> <<2, 3>>
<<0, 1, 2, 3>>

문자열의 자체 바이너리 표현을 볼 수 있는 일반적인 방법은 null 바이트 <<0>>를 문자열에 결합시키는 것 입니다 :

A common trick in Elixir is to concatenate the null byte <<0>> to a string to see its inner binary representation:

iex> "hełło" <> <<0>>
<<104, 101, 197, 130, 197, 130, 111, 0>>

바이너리에 적혀있는 각각의 번호는 1 바이트의 표현이기 때문에 255까지 있습니다. 바이너리는 255보다 큰 수를 저장하거나 코드 포인트를 UTF8 표현으로 변환하기 위해 수식어를 사용할 수 있습니다.

Each number given to a binary is meant to represent a byte and therefore must go up to 255. Binaries allow modifiers to be given to store numbers bigger than 255 or to convert a code point to its utf8 representation:

iex> <<255>>
<<255>>
iex> <<256>> # truncated
<<0>>
iex> <<256 :: size(16)>> # use 16 bits (2 bytes) to store the number
<<1, 0>>
iex> <<256 :: utf8>> # the number is a code point
"Ā"
iex> <<256 :: utf8, 0>>
<<196, 128, 0>>

만약 한 바이트가 8 비트일때, 1 비트만 사용하라는 수식어를 넘기면 어떻게 될까요?

If a byte has 8 bits, what happens if we pass a size of 1 bit?

iex> <<1 :: size(1)>>
<<1::size(1)>>
iex> <<2 :: size(1)>> # truncated
<<0::size(1)>>
iex> is_binary(<< 1 :: size(1)>>)
false
iex> is_bitstring(<< 1 :: size(1)>>)
true
iex> bit_size(<< 1 :: size(1)>>)
1

더 이상 바이너리 값이 아니고 비트스트링 값입니다 -- 단순한 비트들의의 모임! 즉 바이너리는 8개의 비트스트링으로 구성됩니다.

The value is no longer a binary, but a bitstring -- just a bunch of bits! So a binary is a bitstring where the number of bits is divisible by 8!

바이너리와 비트스트링에도 패턴매칭이 됩니다.

We can also pattern match on binaries / bitstrings:

iex> <<0, 1, x>> = <<0, 1, 2>>
<<0, 1, 2>>
iex> x
2
iex> <<0, 1, x>> = <<0, 1, 2, 3>>
** (MatchError) no match of right hand side value: <<0, 1, 2, 3>>

바이너리안에 있는 각각의 값들은 정확히 8비트에 일치해야 하지만 binary 수식어를 통해 나머지 값들을 매칭 시킬수 있습니다.

Note each entry in the binary is expected to match exactly 8 bits. However, we can match on the rest of the binary modifier:

iex> <<0, 1, x :: binary>> = <<0, 1, 2, 3>>
<<0, 1, 2, 3>>
iex> x
<<2, 3>>

위 패턴은 바이너리가 <<>> 의 끝에 있어야 동작합니다. 문자열 결합 연산자 <> 로도 유사한 결과를 얻을 수 있습니다.

The pattern above only works if the binary is at the end of <<>>. Similar results can be achieved with the string concatenation operator <>:

iex> "he" <> rest = "hello"
"hello"
iex> rest
"llo"

비트스트링, 바이너리와 문자열 여행도 이제 끝입니다. 문자열은 UTF-8로 인코딩된 바이너리이며 바이너리는 8개의 비트수를 가집니다. 여기에서는 비트와 바이트를 유연하게 처리 할 수있는 기능을 Elixir가 제공하는걸 봤지만 실제로는 바이너리를 다룰때 99%의 시간은 is_binary/1byte_size/1 함수를 사용하게 될 것입니다.

This finishes our tour of bitstrings, binaries and strings. A string is a UTF-8 encoded binary, and a binary is a bitstring where the number of bits is divisible by 8. Although this shows the flexibility Elixir provides to work with bits and bytes, 99% of the time you will be working with binaries and using the is_binary/1 and byte_size/1 functions.

6.3 문자 리스트 - Char lists

문자 리스트는 말 그대로 문자의 리스트이지 그 이상 그 이하도 아닙니다:

A char list is nothing more than a list of characters:

iex> 'hełło'
[104, 101, 322, 322, 111]
iex> is_list 'hełło'
true
iex> 'hello'
'hello'

보시다시피 작은따옴표로 둘러싸인 문자리스트는 바이트 값 대신에 각 문자의 코드포인트 값을 포함합니다 (iex에서는 ASCII 범위보다 밖에있는 문자를 포함하면 코드 포인트의 값으로 표시된다는점에 주의하십시요). 큰따옴표로 묶인것은 문자열 (즉 바이너리)인 반면에 작은따옴표로 묶인 것은 문자의 리스트 입니다.

You can see that, instead of containing bytes, a char list contains the code points of the characters between single-quotes (note that iex will only output code points if any of the chars is outside the ASCII range). So while double-quotes represent a string (i.e. a binary), single-quotes represents a char list (i.e. a list).

실제로 문자리스트는 Erlang과의 인터페이싱할때 대부분 사용됩니다. 특히, 바이너리를 인자로 허용하지 않는 오래된 라이브러리에 사용되고 있습니다. to_string/1to_char_list/1 함수를 사용하면 문자리스트를 문자열로 변환하거나 그 반대로 할 수 있습니다:

In practice, char lists are used mostly when interfacing with Erlang, in particular old libraries that do not accept binaries as arguments. You can convert a char list to a string and back by using the to_string/1 and to_char_list/1 functions:

iex> to_char_list "hełło"
[104, 101, 322, 322, 111]
iex> to_string 'hełło'
"hełło"
iex> to_string :hello
"hello"
iex> to_string 1
"1"

위 함수들은 다형성 함수입니다. 문자리스트를 문자열로 변환할 뿐만 아니라 정수에서 문자열, 원자형에서 문자열등의 변환에 사용할 수 있습니다.

Note that those functions are polymorphic. They not only convert char lists to strings, but also integers to strings, atoms to strings, and so on.

바이너리, 문자열, 그리고 문자리스트는 여기까지입니다. 이제 키-값 데이터 구조에 대해 살펴봅시다.

With binaries, strings, and char lists out of the way, it is time to talk about key-value data structures.