Pythonでエンディアン変換

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

# 目次
+ [数値文字列をre.subでエンディアン変換](#数値文字列をresubでエンディアン変換)
+ [数値文字列をスライスでエンディアン変換](#数値文字列をスライスでエンディアン変換)
+ [数値をto_bytesでエンディアン変換](#数値をto_bytesでエンディアン変換)

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

```python: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()```で文字列に戻す。

```python: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()```を使う。

```python: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'
```
[戻る](#目次)


参考

https://qiita.com/masakielastic/items/21ba9f68ef6c4fd7692d