質問: 以下のサイトを参考にpythonで自動変換を実施したいです。 方法をご教示頂けないでしょうか どうゆう法則性で変換するのか? なぜサイズが違うのかが全然わかりません Value CBOR JSON 0 1 1 23 1 2 [1, 2, 3, 4] 5 9 リンク内容
回答: | Value | CBOR (バイト列) | CBOR len | JSON (文字列) | JSON len | | --- | --- | --- | --- | --- | | 0 | \x00 | 1 | "0" | 1 | | 23 | \x17 | 1 | "23" | 2 | | [1,2,3,4] | \x84 \x01 \x02 \x03 \x04 | 5 | "[1,2,3,4]" | 9 | こういうことでしょうか。 > > なぜサイズが違うのかが全然わかりません > > > 「バイト」単位でデータを見ても解り難いですが、「ビット」単位だと未使用領域が有り 一般的にバイナリフォーマットでは、ビット単位でメモリを効率良く使うことで省サイズを実現します。 全部説明するとなると膨大な量になるので、 例に挙げられた値のみに絞って説明します。 * 0..23迄の整数 * 0..23迄の長さの配列 0..23 の範囲の整数 * JSONでは、数値の桁数=サイズ * CBORでは変換なし。サイズは常に1 ``` def cbor_encode_number(num): if 24 > num >= 0: # 0..23の範囲 return bytes([num & 0xff]) # 常に1バイト elif 256 > num >= 24: # 24..255の範囲 return bytes([0x18, num & 0xff]) # 常に2バイト else: raise NotImplementedError("no supported out of number 0..255") ``` ※注意。ここでは、理解しやすくするために「数値のリスト」を用いてますが、 実際にバイナリを必要とする場面は、処理速度・省メモリ等の面での 最適化が求められることが多いので、より効率の良い方法で実装されます。 長さ23迄の配列 * JSON では、配列の始点終点の [] に2バイト、区切り文字で 要素数-1の3バイト + データ(1234)の4バイト (2+3+4=計9バイト) * CBOR では1バイト目に配列であることの印とその長さの情報を含みます 小さな数(0..23)の配列であれば、そのデータサイズは 1+要素数 ``` def cbor_encode_array(seq): # 長さ23迄の配列 assert len(seq) < 24 result = bytearray([0x80 | len(seq)]) for val in seq: result.extend(cbor_encode(val)) return bytes(result) def cbor_encode(value): if isinstance(value, int): return cbor_encode_number(value) elif isinstance(value, list): return cbor_encode_array(value) else: raise NotImplementedError("unknown data type") if __name__ == '__main__': print(repr(cbor_encode(0))) # => b'\x00' print(repr(cbor_encode(23))) # => b'\x17' print(repr(cbor_encode([1,2,3,4]))) # => b'\x84\x01\x02\x03\x04' ``` 参考・関連 要バイナリに関する基礎知識: ビット、バイト、16進数、2進数、補数、バイトオーダー、エンディアン、辺り * バイナリデータ処理 * [RFC-7049] Concise Binary Object Representation (CBOR) 実際に自分で実装となると、この辺を参考にすると思います。