80671


以下のコードをPython3.7で実行すると問題なく動作します。

[code]

    import zlib
    
    message = "ababtestabab"
    
    message_test = zlib.compress(message.encode("utf-8"))
    
    # compress()により圧縮したbytesをhex()により16進表記の文字列にする
    m = message_test.hex()
    
    # ここからは逆変換
    # 16進表記の文字列からbytes型へ変換する
    bm = bytes.fromhex(m)
    
    # 圧縮したものをもとに戻す
    bmm = zlib.decompress(bm)
    
    # 最後にbytes型を文字列に戻す
    bmmm = bmm.decode("utf-8")
    print(bmmm)
    
[/code]

しかし、Python2.7で実行すると

`m = message_test.hex()`の行で  
`'str' object has no attribute 'hex'`と言われて実行できませんでした。

`bytes.fromhex(m)`もちゃんと動作しないようです。  
Python2.7で上記のコードを動作させるにはどのように書けば良いですか？


CC BY-SA 4.0
2021-08-07T15:19:57.657
80661
2021-08-08T04:38:08.430
2021-08-08T04:38:08.430
3060
34471
question
python python2
Python2.7でByte型←→16進数文字列の相互変換をするには？


質問するときは環境に関する情報を詳しく記述しましょう。

  * [技術系メーリングリストで質問するときのパターン・ランゲージ](https://www.hyuki.com/writing/techask.html#env)

Python 3の`zlib.compress()`は`bytes`を受け取って`bytes`を返しますが、  
Python 2の`zlib.compress()`は`str`を受け取って`str`を返します。

  * [zlib — Compression compatible with gzip — Python 3.9.6 documentation](https://docs.python.org/3/library/zlib.html#zlib.compress)
  * [12.1. zlib — Compression compatible with gzip — Python 2.7.18 documentation](https://docs.python.org/2.7/library/zlib.html#zlib.compress)

もしバイナリデータと16進数ASCII文字列との間で相互変換をしたいのであれば、`binascii`モジュールを使用します。

  * [18.14. binascii — Convert between binary and ASCII — Python 2.7.18 documentation](https://docs.python.org/2.7/library/binascii.html)

[code]

    # -*- coding: utf-8 -*-
    import zlib
    import binascii
    
    # Unicode 文字列 (unicode) から UTF-8 のバイト文字列 (str) に変換する。
    unicode_message_string = u"ababtestabab"
    utf8_message_string = unicode_message_string.encode("utf-8")
    # または、バイト文字列 (str) が UTF-8 エンコーディングされていると仮定する。
    #utf8_message_string = "ababtestabab"
    
    print "* Origial string:"
    print utf8_message_string
    print "Hex = " + binascii.hexlify(utf8_message_string)
    
    compressed_message_string = zlib.compress(utf8_message_string)
    
    print "* Compressed string:"
    print compressed_message_string
    print "Hex = " + binascii.hexlify(compressed_message_string)
    
    decompressed_message_string = zlib.decompress(compressed_message_string)
    
    print "* Decompressed string:"
    print decompressed_message_string
    print "Hex = " + binascii.hexlify(decompressed_message_string)
    
[/code]

なお、Python 3の`str`型はPython 2の`unicode`型に相当します。  
Python 2の`str`型はバイト文字列です（C言語の`char`型配列に相当）。

  * [Built-in Types — Python 3.9.6 documentation](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str)
  * [5\. Built-in Types — Python 2.7.18 documentation](https://docs.python.org/2.7/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange)

また、Pytyon 3の`print()`は関数 (function) ですが、Python 2の`print`は文 (statement)
です。他にも互換性のない部分が多々あります。

Python 2はすでにサポートが終了しており、セキュリティパッチも提供されないので、今後の使用は推奨されません。


CC BY-SA 4.0
2021-08-07T17:54:44.890
80662
2021-08-07T18:09:17.630
2021-08-07T18:09:17.630
15413
15413
80661
answer


Python2 には future パッケージが提供されています。

[future · PyPI](https://pypi.org/project/future/)

> future is the missing compatibility layer between Python 2 and Python 3. It
> allows you to use a single, clean Python 3.x-compatible codebase to support
> both Python 2 and Python 3 with minimal overhead.

future パッケージの `builtins.bytes` には [`fromhex`
メソッドが実装されている](https://github.com/PythonCharmers/python-
future/blob/master/src/future/types/newbytes.py#L214)のですが `hex`
メソッドがありません(package 内で `encode()` メソッドを使うことができないためです)。そのため、以下のコードでは `hex`
メソッドを追加しています。

[code]

    # -*- coding: utf-8 -*-
    
    from __future__ import print_function, unicode_literals
    import zlib
    
    import sys
    if sys.version_info < (3,):
      from builtins import bytes
      bytes.hex = lambda self: ''.join('{:02x}'.format(i) for i in self)
    
    message = "ababtestabab"
    #message = u"おはよう、世界"
    #message = "おはよう、世界"
    message_test = zlib.compress(message.encode("utf-8"))
    
    # compress()により圧縮したbytesをhex()により16進表記の文字列にする
    m = bytes(message_test).hex()
    
    # ここからは逆変換
    # 16進表記の文字列からbytes型へ変換する
    bm = bytes.fromhex(m)
    
    # 圧縮したものをもとに戻す
    bmm = zlib.decompress(bm)
    
    # 最後にbytes型を文字列に戻す
    bmmm = bmm.decode("utf-8")
    print(bmmm)
    
[/code]


CC BY-SA 4.0
2021-08-07T22:44:09.530
80665
2021-08-07T22:53:29.683
2021-08-07T22:53:29.683
47127
47127
80661
answer


こちらの記事を参考に、`.encode('hex')`と`.decode('hex')`で出来るようです。  
[Python - バイナリファイル、16進数(文字列メソッド(encode、decode)、bytesメソッド(hex、fromhex))
...](https://www.mkamimura.com/2018/08/python-16encodedecodebyteshexfromhex.html)

> > たとえば、 "ABCD".encode('hex') だと、"41424344"となる。逆はdecodeで。  
>  あとは例えば、python -c "print("\x00" * 0x10)"
> でパイプライン使ったり、リダイレクトしたりすると、制御文字やNULL文字の入力されたバイナリファイルを簡単に入力したり保存できたりする。
>
> そんなこと出来たっけ？と気になったので試してみた。  
>  ...途中省略...  
>  出来た。という事で、双葉 杏さんの話はpython 2.7での話だったみたい。(という事で、私の勘違い。m(_ _)m)

ちなみに @metropolis さん回答の`(package 内で encode()
メソッドを使うことができないためです)`というのがどういうことなのかは知識が無く理解できていませんが、以下のように簡単なスクリプトでそのまま使う分には出来るようです。

該当の2行だけ変えています。

[code]

    import zlib
    
    message = "ababtestabab"
    
    message_test = zlib.compress(message.encode("utf-8"))
    
    # compress()により圧縮したbytesをhex()により16進表記の文字列にする
    #### m = message_test.hex()
    m = message_test.encode('hex') #### for Python 2.7
    
    # ここからは逆変換
    # 16進表記の文字列からbytes型へ変換する
    #### bm = bytes.fromhex(m)
    bm = m.decode('hex')           #### for Python 2.7
    
    # 圧縮したものをもとに戻す
    bmm = zlib.decompress(bm)
    
    # 最後にbytes型を文字列に戻す
    bmmm = bmm.decode("utf-8")
    print(bmmm)
    
[/code]


CC BY-SA 4.0
2021-08-08T04:05:45.243
80671
2021-08-08T04:05:45.243
26370
80661
answer