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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Python

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

Q&A

解決済

4回答

1907閲覧

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

yokatone

総合スコア43

Python 3.x

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

Python

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

0グッド

0クリップ

投稿2018/07/19 04:36

解決したいこと

'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進数を経由しなくてもよいです。

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2018/07/19 05:41

究極の目的である「10進数」というのは数値ですか?文字列ですか?
yokatone

2018/07/19 06:17

最終的には数値になります。とはいえ文字列で出てきても問題ありません。
fuzzball

2018/07/19 06:32

回答へのコメントを読むと、究極の目的の入力である「符号付16進数」はバイナリとのことですが、そのバイナリから、今回の質問の入力である「16進数表記のstr型文字列」へはどうやって変換したのでしょうか?
yokatone

2018/07/19 06:35

元々ソケットで叩くと内部保持の値(2進数)を16進数で出す機械があって、socket.recv()の結果がstr型だった、という感じです。
fuzzball

2018/07/19 06:40 編集

ということは、「符号付16進数の文字列」を「(符号付)10進数の数値/文字列」に変換できればいいということですね?(であれば、もう解決ですね?)
yokatone

2018/07/19 06:54

はい、おっしゃる通りです。皆さんの迅速なお力添えのおかげで問題も解決しました。ありがとうございました。 質疑応答をする中で、fuzzballさんはどのあたりが引っかかったのかふと疑問に思ったのですが、 よろしければお聞かせ願えませんでしょうか?
fuzzball

2018/07/19 07:04

「符号付16進数」は文字列だと思っていたのにバイナリだったので確認しました。(結局のところ文字列でしたが)
fuzzball

2018/07/19 07:07 編集

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

2018/07/19 07:09

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

2018/07/19 07:23

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

回答4

0

ベストアンサー

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

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

Python

1import binascii 2import sys 3for h in ['0x12','0xFF','0x0123']: 4 5 # 16進文字列→バイナリ 6 b = binascii.a2b_hex(h[2:]) # 先頭''0x'は不要 7 8 # バイナリ→数値 9 n = int.from_bytes(b,byteorder=sys.byteorder,signed=True) 10 11 print(h,b,n,hex(n),bin(n)) # 変換元の16進文字列、バイナリ、数値の(10進/)16進/2進表現

投稿2018/07/19 05:11

編集2018/07/19 06:44
can110

総合スコア38266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yokatone

2018/07/19 06:17

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

2018/07/19 06:23

あ、`符号付16進数`はバイナリのことでした。 文字列で16進数の符号表現って、`-E8`とかになるんですか? 16進数に符号をつけた表現を知らないので、根本を勘違いしていたらごめんなさい。 もともとは(1)バイナリデータを16進数で受け取って、(2)それを2進数に変換して、(3)ビット反転処理をして、(4)10進数として表現.... といったコードがあって、その(2)の過程で、今回の質問が必要になった、という背景です。
can110

2018/07/19 07:06 編集

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

2018/07/19 07:02

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

2018/07/19 07:09

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

2018/07/19 07:25

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

2018/07/19 07:49 編集

いや、うーん 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が欲しいため) 直接符号をつけて変換する方法もご教示有難うございます!今後役にたつと思います。
can110

2018/07/19 07:44

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

0

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

python

1>>> i = 0xcd 2>>> type(i) 3<class 'int'> 4>>> i 5205

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


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

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

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

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

python

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

投稿2018/07/19 04:47

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yokatone

2018/07/19 06:16

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

0

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

Python

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

投稿2018/07/19 04:45

LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2018/07/19 05:04

質問の最後三行に注目!
yokatone

2018/07/19 06:16

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

0

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

Python

1def hexTobin(hex): 2 return eval(hex)

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

Python

1a = 0xcd

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

python

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

投稿2018/07/19 04:47

編集2018/07/19 07:17
tachikoma

総合スコア3601

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yokatone

2018/07/19 06: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)`と挙動として同じ という理解でよいんでしょうか? 長くなってしまいましたが、お時間があったら教えてください!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問