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つのコードポイントを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ではheoを表現するには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)

Elixirではバイナリを<<>>を使って定義することができます:

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

ヌルバイト`<<0>>を結合させて文字列のバイナリ表現を見ることはElixirにおいて一般的な技法です:

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

バイナリの全てのエントリーはちょうど8bitずつを期待していることに注意してください.しかしバイナリ修飾子を使うことで「残り」へマッチさせることができます:

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.