小ネタ① IPアドレス・MACアドレス
バイトオーダー変換
Cのhtonl()ライクな処理がしたかったのです。
そこは流石pythonですね。
標準でバイトオーダー変換ができるモジュールが用意されていました。
バイトオーダ変換の方法はいくつか見つかったのですが、
その中でも、int→bytes→intで変換する方法が一番簡単かと思いました。
以下は1を32bitでバイトオーダ変換(16777216になる)する例です。
x = 1 y = int.from_bytes(x.to_bytes(4, byteorder=sys.byteorder), byteorder='big')
※バイナリ的にはb’\x01\x00\x00\x00’→b’\x00\x00\x00\x01’の変換
ざっくり解説すると以下の感じでしょうか。int.from_bytes(<変換元の整数>.to_bytes(<変換するbyteの長さ>, byteorder=<変換元のバイトオーダー>), byteorder=<変換したいバイトオーダー>)
ポイントとしては変換するバイト長を間違えないことです。
例えば、IPv4のアドレスの変換を行いたいのであれば、
4(32bit)を指定しないといけません。
(IPアドレスの変換であればipaddress型を使うべきですが)
また、to_bytesで指定するbyteorderにはsys.byteorderを使用するのが無難でしょう。
sys.byteorderでは、自分が使用しているシステムのバイトオーダーを取得できます。
参考↓
https://docs.python.org/ja/3/library/stdtypes.html#additional-methods-on-integer-types
IPアドレス変換(整数値↔︎文字列)
先ほどチラッと触れましたが、IPアドレスの変換であればipaddress型を使うののがベストプラクティスです。
(ipaddress型は高機能な反面、若干遅いと言う問題点もあるので性能が要求される場合は自前でゴリゴリ書きましょう。というか性能重視ならCで…)
IPv4の場合
・整数値→文字列
※以下は0→’0.0.0.0’の変換の例
ipv4_str = str(ipaddress.ip_address(0))
ポイントは、バイトオーダーはシステム(普通はビッグエンディアン)になる点です。
つまり、ネットワークから取得したIPアドレス等を変換したい場合は、バイトオーダーを変換する必要があります。
・文字列→整数値
※以下は’0.0.0.0’→0の変換の例
ipv4_int = int(ipaddress.ip_address('0.0.0.0'))
こちらも先ほどと同じでバイトオーダーはシステム(普通はビッグエンディアン)になるので注意です。
参考
https://docs.python.org/ja/3/library/ipaddress.html?highlight=ipaddress#conversion-to-strings-and-integers
IPv6の場合
・整数値→文字列
str(ipaddress.IPv6Address(1))
IPv4と異なり、明示的にIPv6型を使用する必要があります。
なぜなら、ipaddress型は::1のような32bitにおさまる値を無条件でIPv4として扱ってしまうからです。
・文字列→整数値
IPv4と同じ方法で問題ないです。
※IPv6の場合128bitの整数値の扱いも問題になったりしますが、その辺はstruct等を駆使して頑張りましょう。
参考
https://docs.python.org/ja/3/library/stdtypes.html#built-in-types
https://docs.python.org/ja/3/library/ipaddress.html?highlight=ipaddress#module-ipaddress
MACアドレス変換
・整数値→文字列
※1234→’00-00-00-00-04-d2’の例
import struct "-".join([format(i, 'x').zfill(2) for i in struct.pack("!Q", 1234)[2:]])
やってることとしてはbytes型に変換してイテレータ回して1byteずつ変換しているだけです。
structに6byteに対応するものがないので末尾に[2:]がついてます。
※formatの部分の’x’を大文字にすると16進数のアルファベットの部分を大文字にできます。
・文字列→整数値(需要なさそう)
※’00-00-00-00-04-d2’→1234の例
int(bytearray(int(i, 16) for i in '00-00-00-00-04-d2'.split("-")).hex(), 16)
“-“で分割→1byteずつintに変換→bytearrayにぶちこむ→16進数文字列に変換→intに変換
…ゴリ押し感がすごいですが、変換は正しいです。
参考
https://qiita.com/FmtWeisszwerg/items/c7aa26859c463dda5ebc
コメント