PythonでIPアドレスの文字列表現が正しいフォーマットか確認する


はじめに

タイトルのとおり、Pythonで「192.168.1.100」のようなIPアドレスの文字列が正しいフォーマットか確認する簡単なやり方のメモです。以前は正規表現をがんばって書いていました。

やりかた

from socket import inet_aton

def is_valid_ip(addr):
    try:
        inet_aton(addr)
        return True
    except:
        return False

is_valid_ip("192.168.1.100") # True
is_valid_ip("192.168.1.xxx") # False

以下のライブラリのソースを眺めていて、あーこうやるのかと納得した次第です。

余談

inet_atonが何なのか知らなかったのですが man inet_aton したところ色々わかりました。

man inet_aton
...
DESCRIPTION
       inet_aton()  converts  the  Internet host address cp from the IPv4 numbers-and-dots notation into binary form (in network byte order) and stores it in the structure that inp
       points to.  inet_aton() returns nonzero if the address is valid, zero if not.  The address supplied in cp can have one of the following forms:

       a.b.c.d   Each of the four numeric parts specifies a byte of the address; the bytes are assigned in left-to-right order to produce the binary address.

       a.b.c     Parts a and b specify the first two bytes of the binary address.  Part c is interpreted as a 16-bit value that defines  the  rightmost  two  bytes  of  the  binary
                 address.  This notation is suitable for specifying (outmoded) Class B network addresses.

       a.b       Part a specifies the first byte of the binary address.  Part b is interpreted as a 24-bit value that defines the rightmost three bytes of the binary address.  This
                 notation is suitable for specifying (outmoded) Class A network addresses.

       a         The value a is interpreted as a 32-bit value that is stored directly into the binary address without any byte rearrangement.
...

inet_atonで変換可能なフォーマットは「192.168.1.100」のような見た目以外でも、「3232235876」とか「192.11010404」とか「192.168.356」でもいいみたいです。4オクテットのシリーズでないと正しいとみなさない、といった要件がある場合は、inet_atonに加えてそこのチェックを入れたほうがいいかも。

以下は、「192.168.1.100」と同じ変換結果になるものの変換の例です。

ipython
...
In [1]: from socket import inet_aton

In [2]: hex(192), hex(168), hex(1), hex(100)
Out[2]: ('0xc0', '0xa8', '0x1', '0x64')

In [3]: 0xc0a80164
Out[3]: 3232235876

In [4]: inet_aton("3232235876")
Out[4]: '\xc0\xa8\x01d'

In [5]: 0xa80164
Out[5]: 11010404

In [6]: inet_aton("192.11010404")
Out[6]: '\xc0\xa8\x01d'

In [7]: 0x0164
Out[7]: 356

In [8]: inet_aton("192.168.356")
Out[8]: '\xc0\xa8\x01d'