2016年5月27日金曜日

IPv4にマッチする正規表現

ひょんなことからIPv4のIPアドレスを判定する正規表現を考えることになった。考えた流れをここに残しておくことにする。

IPv4というと

192.168.0.1

こんなやつである。「.」で区切られた4つの0〜255までの数値からなるわけだ。

なので第一歩。
0〜255の数値にマッチする正規表現をXXXとすると
(XXX)\.(XXX)\.(XXX)\.(XXX)
である。

今回は別にキャプチャしたいわけでもないので「(XXX)\.」が3回続くのに注目してまとめることができる。
((XXX)\.){3}(XXX)

あとは肝心のXXXを考えるだけだ。

必要なのは場合分け。それぞれの場合についての表現をX1,X2,X3……とするとXXXは(X1|X2|X3|……)と表せる。

まず1桁の場合。0〜9までなので簡単だ。
[0-9]

続いて2桁の場合。10〜99。1〜9に続けて0〜9が並ぶと言い換えることができるので
[1-9][0-9]

3桁の場合は100の位が1か2かで分ける必要がある。
100〜199については簡単だ。1に続けて0〜9が2回並ぶ。
1[0-9][0-9]
もちろん繰り返しを使って1[0-9]{2}としてもよい。

200〜255についてはさらに場合分けが必要だ。
200〜249に関しては1の位として0〜9をとりうる。よって
2[0-4][1-9]

250〜255は見ての通り1の位に6〜9をとってはいけない。すなわち
25[0-5]

さあ。これだけをまとめていこう。
[0-9]|[1-9][0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5]

これをXXXに当てはめて
(([0-9]|[1-9][0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])

今回の問題は判定する文字列が1行として与えられるものだったので行頭と行末をつけて
^(([0-9]|[1-9][0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])$

ふう。

※あとで調べていたら1桁の場合と2桁の場合はまとめることができることがわかった。[0-9]と[1-9][0-9]を一緒にして[1-9]?[0-9]となり、結果としては[1-9]?[0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5]を用いて
^(([1-9]?[0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9{2}|2[0-4][0-9]|25[0-5])$
と表せる。詰めが甘かった。

こういう場合は[0-9]の代わりに\dを使うと何をしたいのか不明瞭になるな、と考えるなど。

0 件のコメント:

コメントを投稿