unicodeとは？文字コードとは？UTF-8とは？

#　はじめに
タイトルにある通り、文字コードについて学習したことを記載していきたいと思います。

#　文字コードとは

**数字しか認識できないコンピュータが文字を扱うために、人間の文字に対応してそれぞれ割り振られた番号**のこと。
つまりコンピュータは、文字コードを使って我々の文字を数字に変換してから認識をしている。



#　よく聞くUnicodeとは

`Unicode`は**「符号化文字集合」**と言われ、世界中の文字に対して、番号が割り当てられ管理されている**集合体**のこと。

ここで割り振られている番号のことを**コードポイント**と言います。コードポイントは符号位置（文字集合内の文字の位置）であって、符号化方式ではありません。コードポイントは16進数表示で頭にU+を付けて用いられる。

pythonでは以下のようにコードポイントを取得できます。
(python3はユニコード文字列なので、uを付けなくてOK)

```python
>>> ord("あ")
12354
>>> hex(ord("あ"))#16進数表記
'0x3042'
>>> chr(12354)
'あ'

#python2ならuをつける
>>> ord(u"あ")
12354
```

ここからさらに数値変換（文字符号化方式＝encoding）で使われるのが**「符号化形式」**というもので、有名なのが`UTF-8、UTF-16、UTF-３２`などです。

つまり
**unicode≠UTF-8
unicode≠UTF-16
unicode≠UTF-32**
です。

符号化文字集合：Unicode
文字符号化方式：UTF-8、UTF-16、UTF-32 など

#　ところでASCIIコードって

**ASCII**【American Standard Code for Information Interchange】
`「符号化文字集合」`のひとつで、最も基礎となる文字コード。数字、アルファベット、記号を1バイトで表現します。
「文字に割り当てた番号」と「コンピュータが扱う数字」が同じなので、文字符号化方式を意識する必要がないです。

#　ところでShift-JISって

ASCIIコードの文字に日本語の文字を加えたのが、**Shift-JIS**です。
現在はJIS(日本工業規格)で規定されています。
半角カタカナは1バイト、それ以外の全角文字は2バイトで表現します。

特徴として、文字コードの領域に**「外字領域」**と言われる「使っていない文字コードの領域」があり、この領域で独自に文字の設定を行うなど拡張することができます。
そのうちの一つが、Windowsなどで使われている`MS932`です。

ちなみに「こんにちは」をShift-JIS 2進数で表現すると以下のようになります。
2進数では見ずらいので、16進数で表記をします。

|日本語       |       Shift-JIS(2進数) |    Shift-JIS(16進数)    |
|:------------:|:------------------|:------------------:|
|こ|              1000001010110001 |        82b1        |
|ん          |            1000001011110001 |       82c9       |
|に           |             1000001011001001 |        82c9        |
|ち           |            1000001010111111 |         82bf         |
|は           |             1000001011001101 |       82cd       |


先ほどと同じ表現をするならば
符号化文字集合：JIS X 0208
文字符号化方式：Shift-jis (拡張されたものがMS932)
となります。

#　UTF-8とは

上で述べたようにUnicode用の符号化方式の1つ。
ASCIIと同じ部分は1バイトで表現し、そのほかの部分を2〜6バイトで表現する可変長の符号化方式となっています。漢字、仮名文字は3〜4で表現する。
ASCIIコードとの互換性が良いため、パソコンで扱いやすく、世界中のソフトウェアで最も使われている。※UTF-16と比較するとデータサイズが大きくなる

UTF-8にはBOMが付けられていません。ただ、UTF-8であれば各バイトの順番をチェックすることによりビッグエンディアンなのかリトルエンディアンなのか判別できるのでBOMを付与されない場合が多いです。

>参考 – エンディアンとは
エンディアンとは複数バイトで構成されるデータの並べ方の事で、ビッグエンディアンとリトルエンディアンがある。例えば「0xABCD」という、2バイトのデータがあったとき、これを「ABCD」と並べるか「CDAB」と並べるかが異なる。前者がビッグエンディアン、後者がリトルエンディアンである。人の目から見ると「ABCD」の方が分かりやすいけど、コンピュータ視点で見ると「CDAB」の方が操作しやすい。
（計算は下の桁から始めるから、下位バイトが先に読み込めた方がコンピュータ的には都合が良い。人には見にくいけど）

[文字コード考え方から理解するUnicodeとUTF-8の違い | ギークを目指して](http://equj65.net/tech/charcode/)

>参考 – BOM（Byte Order Mark）とは
Unicodeの符号化方式を識別するためのテキストデータの先頭に付与される数バイトのデータを意味します。

[UnicodeをUTF-8などの文字コードに変換する方法 | UX MILK](https://uxmilk.jp/49011)


|日本語       |         UTF-8    |
|:------------:|:------------------:|
|こ|e38193|
|ん          |e38293|
|に           |e381ab|
|ち           |e381a1|
|は           |e381af|

- winのメモ帳などでの文字コード対応

Windowsのメモ帳などでも様々な文字コードを扱うことができます。
メモ帳の保存画面の「文字コード」で、「Unicode」を選択すると、符号化方式は自動的にUTF-16（リトル・エンディアン）で保存されます。そして「Unicode（Big Endian）」はUTF-16（ビッグ・エンディアン）に、「UTF-8」はそのままUTF-8の符号化方式を採用します。

#　文字化けについて
文字コードの変換処理は、文字変換ツールやテキストエディタの機能によって行うことができますが、変換がうまくいかず「?」や「■」などに文字化けすることがあります。

#　文字化けの要因
- 「文字コード」の指定を間違えたことによるもの
- デフォルトの設定によるもの
- そもそもコード間での対応がないもの


CSVファイルを開いた時に文字化けして表示されることなどがあります。
Excel日本語版がCSVファイルを読み込む際のデフォルト文字コードはShift-JISと設定されています。そこにUTF-8で格納されたデータを読み込んだ結果、文字化けが発生する仕組みです。

他にも、上記で記載した通り、各文字コードには、表現できる文字の範囲があり、対応していない文字の場合は、変換できずに代替文字が割り当てられるために起きます。
特にShift-JISと、UTF-8やUTF-16の変換で発生しやすいです。
上で記載したShift-JISの外字領域にある文字は、UTF-8などではうまく変換されない場合があります。

#　str型とbytes型について

Python3では
- str型はUnicode文字を実体としている

```python
>>> type("あ")
<class 'str'>
```

```python
>>> ord("あ")
12354
>>> hex(ord("あ"))
'0x3042'
```

- bytes型はUTF-8やUTF-16でエンコードされたバイトシーケンスを実体としている

```python
>>> "あ".encode('utf-8')#UTF-8でエンコード#[\x]を外して読めば上記の表で記載した形になる
b'\xe3\x81\x82'
>>> type(b'\xe3\x81\x82')
<class 'bytes'>
>>> b'\xe3\x81\x82'.decode('utf-8')#デコード
'あ'
```

ちなみにpython3でのデフォルトエンコーディングはUTF-8行われています。
※python2ではasciiです。

```python
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
```

#　補足：◯進数について

補足的に、すでに上で記載していた、通常の10進数だけでなく2進数、8進数、16進数などでの数値や文字列を取り扱いについて記載します。


###### 整数を2進数、8進数、16進数に変換
プレフィックス`0b, 0o, 0x`をつけると、整数型intの数値をそれぞれ2進数、8進数、16進数として扱うことができます。※プレフィックスがついても、型としては整数型intは維持されます。当然四則演算がも可能。

```python
>>> bin_num = 0b10
>>> oct_num = 0o10
>>> hex_num = 0x10
>>> print(bin_num)
2
>>> print(oct_num)
8
>>> print(hex_num)
16
>>> print(type(bin_num))
<class 'int'>
```


bin(), oct(), hex()

```python
>>> ord("あ")
12354
>>> hex(ord("あ"))
'0x3042'
```


#　参考
- [エクセルを利用してUnicode(Unicode Code Point)からUTF-8に変換する](https://igreks.jp/dev/%E3%82%A8%E3%82%AF%E3%82%BB%E3%83%AB%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6unicodeunicode-code-point%E3%81%8B%E3%82%89utf-8%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B/)
- [Unicode文字ツール](https://www.marbacka.net/msearch/tool.php#ucp2enc)

#　おわり