文字列、Byte、Binary


文字列、Byte、Binaryが混乱していたので、ちょっと自分の整理のため。

PythonでByte列を扱う場面は、（1）外部のプログラム等とバイト列で文字列をやりとりする場合（文字列をJsonなどで送受信するとき）、（2）RaspberryPiなどを用いたGPIOの制御の場合。特に、制御系では、Python2のコードも多く、文字列とByte列の区別が明確でなかった（文字列とByte列の結合が容易にできる）が、Python3では扱いが厳密になっている。

参考：Python2とPython3での文字列、バイト列の扱いの違い

[python3のbytes型とstr型の比較と変換方法](https://python.civic-apps.com/python3-bytes-str-convert/)



###　1.　ビットとバイトについて

基本ですが、

***ビット***：2進数（0と1、バイナリ）で表した数字の桁数。

4ビットのデータ（4桁の2進数）は 0～15 までの16通りの数字を表すことができる（2の4乗＝16）。
8ビットのデータ（8桁の2進数）は 0～255 までの256通りの数字を表すことができる（2の8乗＝256）。

***バイト***：8ビットで1バイト。1バイト（256通り）の数字を表すのに16進数を使うと便利。

256＝16×16なので，1バイトの数字がちょうど2桁の16進数で表せる。

参考：

[ビットとバイトの違いが覚えられない・・・。 - 中央線に乗って考える](http://savoia.hatenablog.jp/entry/8bit-byte)
コメントいただいたshiracamusさんの記事です。バイナリーのことが詳しく書かれています。
[プログラムとバイナリ](https://qiita.com/shiracamus/items/8a47d969243810d57428)




### 2.　文字コード

各文字に割り当てられるバイト表現。

参考：[文字コード](https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89)

Wiki引用：

文字コードは文字の集合の各文字に一意なバイト表現を割り当てただけのシンプルなものだった（アスキーコードなど）。バイト値を計算によって変形した符号化表現が用いられるようになってきたため（例えば Shift_JIS や UTF-8）、「符号化文字集合」と「文字符号化方式」とを区別するようになったと考えられる。



**ASCIIコード**：英語圏などで使われる限られた文字集合（7ビットを使用し最大128文字。）

**Unicorde**：世界中の文字を単一文字集合として扱う符号化文字集合



参考：Python2がベースですがUnicodeについて書かれています。

[Unicode文字列(ユニコード文字列)](https://www.javadrive.jp/python/string/index5.html)



### 3.　符号化

**UTF-8**：Unicordeを可変長（1-4バイト）の8ビット符号単位で表現する文字符号化スキーム。ASCIIに対して上位互換している。（一番使われている方式）。他の方式もある。

**Base64**：データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式。MIMEによって規定されていて、7ビットのデータしか扱うことの出来ない電子メールにて広く利用されている。




###　4.　Python3における文字列、バイト列への変換
主に（1）の用途で用いられる。python3で文字列はユニコードに統一されている。

例、日本語の’あ’と、英語の'a'のUnicodeの値

```py
＃Unicode 文字を表す文字列に対し、その文字のUnicode コードポイントを表す整数を返す。
>>> ord("あ")
12354
>>> ord("a")
97

＃()内の整数を"0b"のついた2進文字列に変換
>>> bin(ord("あ")）
0b11000001000010
>>> bin(ord("a"))
0b1100001   #7bit

＃()内の整数を"0x"のついた16進文字列に変換
>>> hex(ord("あ"))
0x3042　    ＃16進数に変換　3042　ユニコード表と一致
>>> hex(ord("a"))
0x61		＃16進数に変換　0061　ユニコード表と一致

＃（）内がUnicode コードポイントの整数に対し、文字列を返す。 
>>> chr(ord("あ"))
あ
>>> chr(12354)
あ
>>> chr(ord("a"))
a
>>> chr(97)
a

#UTF-8で符号化してByte列で出力
>>> "あ".encode()
b'\xe3\x81\x82'
>>> "a".encode()
b'a'

#Byte列を文字列に戻す
>>> b'\xe3\x81\x82'.decode()
あ
>>> b'a'.decode()
a
```

参考：文字列とバイト列の相互変換について

[Python 3 での文字列とバイト列の相互変換と16進数表示](https://qiita.com/masakielastic/items/2a04aee632c62536f82c)



例：base64への変換

```py
import base64
s = "あ".encode()
ss= "a".encode()

#Byte列しか受け付けません。
t = base64.b64encode(s)
tt = base64.b64encode(ss)

print(t)
＃b'44GC'

print(tt)
＃b'YQ=='
```

参考：[Pythonでbase64を扱う](http://kaworu.jpn.org/python/Python%E3%81%A7base64%E3%82%92%E6%89%B1%E3%81%86)



###　5.　Python3での数字の表し方

10進数　97　

16進数　0ｘ61

2進数　0b1100001

参考：2進数/10進数/16進数/文字列の変換

[pythonでの型変換](https://qiita.com/y_sk256/items/2a6b95c2b8ab099ce701)

参考：2進数/10進数/16進数/文字列の変換や演算など

[Pythonで2進数、8進数、16進数の数値・文字列を相互に変換](https://note.nkmk.me/python-bin-oct-hex-int-format/)




### 5.　Binaryデータ　

主に（2）の用途で用いる。主に用いられるモジュールはstruct, binascii。

バイナリーデータでは、コンピューターのプロセッサーがどのようにバイトに分割するかのエンディアンや整数の符号ビットなどの概念を知っておく必要がある。

struct モジュールは、細かくフォーマットを指定してバイナリデータを作成したり、バイナリデータから数値等に変換を行うことができます。Cのデータ型とpythonのデータ型の相互変換に利用できる。

binasciiモジュールは、バイナリと ASCII コード化されたバイナリ表現との間の変換を行うための多数のメソッド提供している。

参考：structモジュールを使う方法とctypes.Structureクラスを使う方法の解説

[pythonのstructモジュールを触ってみる](http://komaken.me/blog/2014/05/30/python%E3%81%AEstruct%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/)

[PythonでバイナリをあつかうためのTips](https://qiita.com/pashango2/items/5075cb2d9248c7d3b5d4)

[Pythonのstructモジュールの使い方【初心者向け】](https://techacademy.jp/magazine/19058)

[struct  - パックされたバイナリデータとしてバイトを解釈する ](http://code.i-harness.com/ja/docs/python~3.6/library/struct)



例：binascii

```py
import binascii

>>> binascii.hexlify('a'.encode()) 
# => b'61'

>>> binascii.b2a_hex(b'a')  #ASCIIコードのみ ｂ’ASCII文字列’でバイナリーとして認識する。
# => b'61'

>>> binascii.hexlify('あ'.encode('utf-8')) 
# => b'e38182'
>>> binascii.b2a_hex('あ'.encode('utf-8')) 
# => b'e38182'

```

参考：[16進文字列と文字列の変換](https://qiita.com/atsaki/items/6120cad2e3c448d774bf)