質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.51%

jsonをCBORに変換したい

解決済

回答 2

投稿

  • 評価
  • クリップ 3
  • VIEW 180

pokemonta

score 27

以下のサイトを参考にpythonで自動変換を実施したいです。
方法をご教示頂けないでしょうか

どうゆう法則性で変換するのか?
なぜサイズが違うのかが全然わかりません

Value    CBOR JSON
0       1   1 
23       1   2 
[1, 2, 3, 4] 5   9 

リンク内容

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+3

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進数、補数、バイトオーダー、エンディアン、辺り

実際に自分で実装となると、この辺を参考にすると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/26 17:01 編集

    > "24..27 はそれ以上の値を表すときの型情報となります"とは
    >2バイトで00000000 00011000~00000000 11111111(24...65535)まで

    24 (0x18) の時は 1バイト(8bit数値) 24..65535 (8ビットで表せる範囲
    25 (0x19) の時は 2バイト(16bit数値) 65536 ... (2**16)-1 (16ビットで表せる範囲
    26 (0x20) の時は 4バイト(32bit数値) (2**16) .. (2**32)-1 (32ビットで表せる範囲
    27 (0x20) の時は 8バイト(64bit数値) ~となります。(CBOR仕様Major type 0より)

    キャンセル

  • 2020/03/29 14:07

    ありがとうございました。↓が何を表してるかはわかりませんでした。
    X:
    O:
    あと、24 (0x18) の時は 1バイト(8bit数値) 24..65535 (8ビットで表せる範囲
    ではなく、24,..255ではないでしょうか

    キャンセル

  • 2020/03/29 19:08 編集

    すいません、ずれてますね。 24..255 です
    16ビットでの値の範囲は 256..65535

    >"24..27 はそれ以上の値を表すときの型情報となります"とは
    2バイトで00000000 00011000~00000000 11111111(24...65535)まで0> 表現するという意味でしょうか?

    X: 00000000 00011000~00000000 11111111(24...65535
    O: 00011000 00011000~00011000 11111111(24...255 訂正

    の部分。2進数で見た時の表記です。
    ここの「2バイト」が何処を指しているのか解りませんが、
    24..27の時、その後に続くデータのサイズは可変なので、
    00000000 00011000 のようにはなりません。

    型情報を含む場合は 00011000 00011000 の計2バイト、
    もしくはデータ部分のみをさす場合は 00011000 の1バイトになります。

    キャンセル

+1

「python CBOR」でググると、1番目と2番目に以下のモジュールが出てきました。
cbor · PyPI
cbor2 · PyPI

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる