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

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

ただいまの
回答率

90.35%

  • Python

    9100questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7311questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python3.xでの16進数 -> 2進数の変換について

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 638

yokatone

score 29

 解決したいこと

'0xcd'などの16進数表記のstr型文字列を
'0b11001101'といった2進数に変換したい

 取り組んだこと

関数として

def hexTobin(hex):
    return bin(hex)


のようなものを実現したいです。

bin(0xcd)を行うと0b11001101が出力されるので、簡単かと思ったのですが
いざbin('0xcd')として、文字列を代入すると
TypeError: 'str' object cannot be interpreted as an indexと、str型を受け付けていないというエラーが発生します。

bin(hex)といった代入ができ、変換した結果の出力ができればよい
hexは文字列

といった制限があるので、hexを何かしらの形で、binの引数としてふさわしい形式に変換し
2進数出力、ないしはbinを使わずにhex文字列を2進数出力できればと思います。
bin()に代入する正しい形を調べようとはしましたが、
公式リファレンスでは単なるxとの表記で、入るべきtypeがわかりませんでした。

ほか、この関数を作った究極の目的としては、"符号付16進数を10進数に修正したい"といったものなので、
これが実現できれば、2進数を経由しなくてもよいです。

以上になります。解決方法についてご存知の方おられましたら、何卒お力添えください。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2018/07/19 16:06 編集

    あと、早々に解決となる回答が付いているのに、次々と回答が付いたので、回答者の人たちも混乱しているのかなぁなどと思いまして。(これは、ほぼ同時刻に複数の回答が付いたためでしたが)

    キャンセル

  • fuzzball

    2018/07/19 16:09

    あれ、can110さんの回答がベストアンサーなんですか?私がなにか勘違いしてるのかな‥。まぁ解決したのならいいです。(お気になさらず)

    キャンセル

  • yokatone

    2018/07/19 16:23

    符号付10進文字列->2進数->16進数-[socket]-16進数->符号あり/なしの判断->2進数->符号付10進文字列 ですもんね。複雑で私も説明に混乱があったかと思います。すみません。(いまだに混乱してる気がします。) 「符号付16進数」=「符号付2進数(バイナリ)」でして、can110さんの説明を借りれば`-0x20`ではなく`0xE0`と表記されるsigned16進数です。 対応するデータがsigned/unsignedであるかどうかのパラメーターはプログラム側で持っていて、 これをsignedの場合は「符号付2進数」と解釈し、補数によって符号付の10進表記文字列(`-32`)を導出したい といった感じでした。質問にご対応いただき有難うございました!

    キャンセル

回答 4

checkベストアンサー

+6

"符号付16進数を10進数に修正したい"

符号付16進数が文字列なのかバイナリなのか不明ですが、binascii.a2b_hexint.from_bytesでどうでしょうか?
バイトオーダーはお好み(仕様に沿って)で。

import binascii
import sys
for h in ['0x12','0xFF','0x0123']:

    # 16進文字列→バイナリ
    b = binascii.a2b_hex(h[2:]) # 先頭''0x'は不要

    # バイナリ→数値
    n = int.from_bytes(b,byteorder=sys.byteorder,signed=True)

    print(h,b,n,hex(n),bin(n)) # 変換元の16進文字列、バイナリ、数値の(10進/)16進/2進表現

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/19 15:17

    おー!二進数に戻してビット反転させてましたが、絶対こんな面倒なことしなくてもいいはず....
    とは思っていました。これがまさに欲しい関数です!問題解決に加えて更なる発展まで有難うございます。

    キャンセル

  • 2018/07/19 15:23

    あ、`符号付16進数`はバイナリのことでした。
    文字列で16進数の符号表現って、`-E8`とかになるんですか?
    16進数に符号をつけた表現を知らないので、根本を勘違いしていたらごめんなさい。

    もともとは(1)バイナリデータを16進数で受け取って、(2)それを2進数に変換して、(3)ビット反転処理をして、(4)10進数として表現....
    といったコードがあって、その(2)の過程で、今回の質問が必要になった、という背景です。

    キャンセル

  • 2018/07/19 15:38 編集

    バイナリデータ自体は数値ですらないので正も負もなく、そのバイト(ビット)パターンが存在するだけです。
    で、それを数値として扱う(変換する)場合にそのビットパターンを「符号付」「符号なし」どちらとみなすかを決定する必要があります。
    例えば「E0」は、符号付だと「-32」、符号なしだと「224」になります。
    さらに、いったん数値になったものをn進文字列として表現する場合には負値には「-」をつけて表現するのが自然かと思います(じゃないと正負見分けがつかない)。
    実際「hex(-32)」の実行結果は「-0x20」になりますね。
    なんか違和感ありますが。

    キャンセル

  • 2018/07/19 16:02

    なるほど。符号付にしたときの先頭ビット情報は、あくまで符号あり/なしという
    プログラム側の型によって意味を持つものであって、同様に
    明示的に符号をn進数自体につけることで、可読性が高まるという表現方法なんですね。
    確かに`-0x20`はかなり違和感がありますが、`0xE0`だけだとunsigned/signedは
    みた感じではわかりませんもんね。有難うございます!

    キャンセル

  • 2018/07/19 16:09

    そうですね。
    よく考えたら、数値になったものであれば
    何進表現だろうと負値にはマイナス記号をつけないと正負区別がつきませんね。

    キャンセル

  • 2018/07/19 16:25

    追記・修正依頼のコメントの流れを読んでなかったのですが
    もしかして「-0xE0」のような文字列を数値「-224」に変換したいのであれば私の回答ではできません。
    素直に「int('-0xE0',16)」でよいです。
    すでに解決されていればいいのですが、なんかモヤモヤ。

    キャンセル

  • 2018/07/19 16:40 編集

    いや、うーん
    param = {'param1': { 'signed': True }, 'param2': { 'signed': False } ... }
    で、
    data = [{'param' : 'param1', 'data': '0xE0'}, {'param': 'param2', 'data': '0xE0'} ...]
    だったとしたら、

    def hexToDecimalWithSign: ... # = 今回の16進数->符号付10進数変換関数
    print(hexToDecimalWithSign(data[0])) # = -32
    print(hexToDecimalWithSign(data[1])) # = 224

    です。`-0xE0`といったような、16進数に直接符号を付与することは想定していません。
    そもそも取得する16進自体からは符号情報は失われている想定で、
    後から符号のあり/なしを16進数に対してかけるイメージです。
    このため2進数に一度戻す必要があり、そこで今回の質問に至ったわけです。

    やはりsignedだからといって取得した`0xE0`に符号をつけて、`-0xE0`という形にしてしまうと、
    すでにビット反転後なので、正しい値とはなりませんので、
    いちど2進数に戻してから変換をかける必要が出てきます。(-224ではなく-32が欲しいため)

    直接符号をつけて変換する方法もご教示有難うございます!今後役にたつと思います。

    キャンセル

  • 2018/07/19 16:44

    >「符号付16進数」=「符号付2進数(バイナリ)」でして
    追記・修正依頼のコメント読みました。
    なるほどバイナリとして解釈してよいので回答コードで可能ですね。
    了解です。解決して良かったです。

    キャンセル

+2

数値化してからbinに放り込んでやると良いでしょう。

>>> bin(int('0xcd', base=16))
'0b11001101'

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/19 14:04

    質問の最後三行に注目!

    キャンセル

  • 2018/07/19 15:16

    baseで一旦10進数に戻せるんですね。ありがとうございます。

    キャンセル

+2

0xcdはint型(整数型)です。

>>> i = 0xcd
>>> type(i)
<class 'int'>
>>> i
205

binのリファレンスにも、「整数を先頭に "0b" が付いた 2 進文字列に変換します」と書いてあります。


とりあえず、intに型変換します。int()の第二引数に0を指定するとそのような挙動になります。

基数 2, 8, 16 のリテラルは、別の記法としてコード中の整数リテラルのように 0b/0B, 0o/0O, 0x/0X を前に付けることができます。 基数 0 はコードリテラルとして厳密に解釈することを意味します。 

2. 組み込み関数 — Python 3.6.5 ドキュメント #int

あとはbin()で変換すればいいです。

>>> hs = "0xcd"
>>> bin(int(hs, 0))
'0b11001101'

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/19 15:16

    こうやって引数のtypeは確認するんですね。大変参考になりました!ありがとうございます。

    キャンセル

+1

16進数リテラルの文字列を数値にするだけならevalでいいんじゃないでしょうか。

def hexTobin(hex):
    return eval(hex)

evalは与えられた文字列をソースコードとして実行する命令です。0xcdは16進数整数リテラルなので、

a = 0xcd


と代入することができます。今、s='0xcd'のように、sの中に"16進数整数リテラル"の文字列があるとすると、欲しいのはsの中身をPythonに実行(or評価)させた結果です。この実行命令がevalです。ただし、evalを使うとコードインテリセンスが働かなかったり、hexにおかしな値を食わせてもPythonコードとして実行可能ならエラーなしに通ってしまうので、いい作法とはあまり言えませんので、int(s, 0)のほうがいいと思います。

eval("a = 2")
print(a)  # <- 実行できるが、aが定義されてないと怒られる

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/19 15:17

    evalっていまいち難しくて使い方がわからなかったのですが、
    こんな便利な使い方があるんですね!
    結局よく挙動がわからないですが....

    hex_int = 0xCD ...type='int'
    hex_str = '0xCD' ...type='str'

    ではあるが、`eval(hex_str)`が`int`と評価されて`205`になって、
    bin(eval(hex_str))で'0b11001101'が出力、ですかね?
    evalは`eval("2 + 5")`を行った時`7`を出力するように、str型の中身を式として評価するため
    ダブルクオテーションが外されるため、実質`eval('0xCD')`は`int(0xCD)`と挙動として同じ
    という理解でよいんでしょうか? 長くなってしまいましたが、お時間があったら教えてください!

    キャンセル

同じタグがついた質問を見る

  • Python

    9100questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7311questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。