LoginSignup
0
0

Pythonでエンディアン変換

Last updated at Posted at 2024-05-01

はじめに

16進数の数値文字列や数値のエンディアンをLittle⇔Bigへ相互変換する方法をまとめる。組み込みソフト開発で、通信ログ解析の時や、バイナリ列のエンディアン変換が必要なときに重宝する。

目次

数値文字列をre.subでエンディアン変換

re.subのグループ化を使ってエンディアン変換。例えば16bitなら4文字の数値を(..)(..)で2文字ずつグループ化して、\2\1で順番変換すれば、エンディアン変換に相当する。re.subなので、連続して変換し続けることができるので、文字列が長くても連続変換できる。元に戻したい場合は、もう一度同じ処理をすれば良い。

endian_sample.py
import re

hex_original = '0123456789ABCDEF'
endian_16bit = re.sub(r'(..)(..)',r'\2\1',hex_original)
endian_32bit = re.sub(r'(..)(..)(..)(..)',r'\4\3\2\1',hex_original)
endian_64bit = re.sub(r'(..)(..)(..)(..)(..)(..)(..)(..)',r'\8\7\6\5\4\3\2\1',hex_original)
print(f'# {hex_original=}\n# {endian_16bit=}\n# {endian_32bit=}\n# {endian_64bit=}')

# hex_original='0123456789ABCDEF'
# endian_16bit='23016745AB89EFCD'
# endian_32bit='67452301EFCDAB89'
# endian_64bit='EFCDAB8967452301'

revert_16bit = re.sub(r'(..)(..)',r'\2\1',endian_16bit)
revert_32bit = re.sub(r'(..)(..)(..)(..)',r'\4\3\2\1',endian_32bit)
revert_64bit = re.sub(r'(..)(..)(..)(..)(..)(..)(..)(..)',r'\8\7\6\5\4\3\2\1',endian_64bit)
print(f'# {revert_16bit=}\n# {revert_32bit=}\n# {revert_64bit=}')

# revert_16bit='0123456789ABCDEF'
# revert_32bit='0123456789ABCDEF'
# revert_64bit='0123456789ABCDEF'

戻る

数値文字列をスライスでエンディアン変換

スライスのステップ[::-1]を使って逆順にすることでエンディアン変換をする。ただし、2文字ずつ逆順にする必要があるので、数値文字列をバイト列に変換して1byteの数値にしてから変換、その後hex()で文字列に戻す。

endian_sample.py
# 16bit数値文字列============
hex_original = '0123'
endian_16bit = bytes.fromhex(hex_original)[::-1].hex()
print(f'# {hex_original=}\n# {endian_16bit=}')

# 32bit数値文字列============
hex_original = '01234567'
endian_32bit = bytes.fromhex(hex_original)[::-1].hex()
print(f'# {hex_original=}\n# {endian_32bit=}')

# 64bit数値文字列============
hex_original = '01234567ABCDEF'
endian_64bit = bytes.fromhex(hex_original)[::-1].hex()
print(f'# {hex_original=}\n# {endian_64bit=}')

戻る

数値をto_bytesでエンディアン変換

to_byte()で変換バイト数と big or little を指定して、数値のエンディアンを変換する。変換した数値を数値文字列に変換する場合はhex()を使う。

endian_sample.py
# 16bit数値============
num = 0x0123
num_big=num.to_bytes(2, 'big')
num_big_str=num.to_bytes(2, 'big').hex()
num_little=num.to_bytes(2, 'little')
num_little_str=num.to_bytes(2, 'little').hex()
print(f'# {num=:04X}\n# {num_big=}\n# {num_big_str=}\n# {num_little=}\n# {num_little_str=}')

# num=0123
# num_big=b'\x01#' =>\x01\x23
# num_big_str='0123'
# num_little=b'#\x01' =>\x23\x01
# num_little_str='2301'


# 32bit数値============
num = 0x01234567
num_big=num.to_bytes(4, 'big')
num_big_str=num.to_bytes(4, 'big').hex()
num_little=num.to_bytes(4, 'little')
num_little_str=num.to_bytes(4, 'little').hex()
print(f'# {num=:08X}\n# {num_big=}\n# {num_big_str=}\n# {num_little=}\n# {num_little_str=}')

# num=01234567
# num_big=b'\x01#Eg' =>\x01\x23\x45\x67
# num_big_str='01234567'
# num_little=b'gE#\x01' =>\x67\x45\x23\x01
# num_little_str='67452301'


# 64bit数値============
num = 0x0123456789ABCDEF
num_big=num.to_bytes(8, 'big')
num_big_str=num.to_bytes(8, 'big').hex()
num_little=num.to_bytes(8, 'little')
num_little_str=num.to_bytes(8, 'little').hex()

print(f'# {num=:016X}\n# {num_big=}\n# {num_big_str=}\n# {num_little=}\n# {num_little_str=}')

# num=0123456789ABCDEF
# num_big=b'\x01#Eg\x89\xab\xcd\xef' =>\x01\x23\x45\x67\x89\xab\xcd\xef
# num_big_str='0123456789abcdef'
# num_little=b'\xef\xcd\xab\x89gE#\x01' =>\xef\xcd\xab\x89\x67\x45\x23\x01
# num_little_str='efcdab8967452301'

戻る

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0