質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.37%

  • Python 3.x

    2398questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 正規表現

    566questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python3 正規表現を用いてIPアドレスを判定したい

解決済

回答 4

投稿 2017/11/23 16:36

  • 評価
  • クリップ 0
  • VIEW 166

yuyu127

score 2

PythonでIPアドレスを正規表現でマッチさせようとしましたが、
すべてFalseとなってしまいます。
下記の場合、Trueとしたいのですが、Falseとなります。
解決方法はありますでしょうか。

address = "1.2.3.4"

m = re.match('\^(([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])$/', address)

if m:
    print("Ture")
else:
    print("False")

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+5

註:以下の回答は、正規表現に関するものではありません。
何らかの制約や目標があって正規表現を用いたいなら、あまり参考にはならないと思います。

IPアドレスに関する標準ライブラリを利用するのが良いと思います。

>>> import ipaddress
>>>
>>> ipaddress.ip_address('1.2.3.4')
IPv4Address('1.2.3.4')
>>>
>>> ipaddress.ip_address('1.2.3.300')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\ProgramData\Miniconda3\lib\ipaddress.py", line 54, in ip_address
    address)
ValueError: '1.2.3.300' does not appear to be an IPv4 or IPv6 address

こういう関数を作ってもいいかもしれませんね。

import ipaddress

def is_valid_ip(arg):
    try:
        ipaddress.ip_address(arg)
        return True
    except ValueError:
        return False

参考までに

CPythonの実装を見てみると、案外ゴリゴリやってるみたいですね。

@classmethod
def _ip_int_from_string(cls, ip_str):
    """Turn the given IP string into an integer for comparison.
    Args:
        ip_str: A string, the IP ip_str.
    Returns:
        The IP ip_str as an integer.
    Raises:
        AddressValueError: if ip_str isn't a valid IPv4 Address.
    """
    if not ip_str:
        raise AddressValueError('Address cannot be empty')

    octets = ip_str.split('.')
    if len(octets) != 4:
        raise AddressValueError("Expected 4 octets in %r" % ip_str)

    try:
        return int.from_bytes(map(cls._parse_octet, octets), 'big')
    except ValueError as exc:
        raise AddressValueError("%s in %r" % (exc, ip_str)) from None
  1. 空だったらダメ
  2. ドットで区切って四つじゃなかったらダメ
  3. 範囲外だったらダメ

追記

正規表現を使っていないのに、BAを貰ってしまったので。
質問者様のコードは、ちょっと修正すればちゃんと動きます。

m = re.match('(([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])', address)

問題のあった点

  • エスケープすべきでない文字をエスケープしていた
  • しかしながらそもそもre.matchなら文頭記号と文末記号は不用
  • 無駄な空白が入っていた
  • 文末の一文字も余計だった(文末記号以降にオプション付ける文法とかありましたっけ...?)
import re
import random

def get_random_address():
    return '{}.{}.{}.{}'.format(
        *[random.randrange(255) for _ in range(4)]
    )

compiled_pattern = re.compile('(([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])')
for _ in range(10000):
    address = get_random_address()
    if not compiled_pattern.match(address):
        print('False', address)

print('True')

一応上記のゴリゴリテストを通過します。
正規表現あんまり得意じゃないので、変なこと書いていたらすみません。

投稿 2017/11/23 16:39

編集 2017/11/27 13:18

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/23 17:00

    LouiS0616様
    ご回答ありがとうございます。
    正しい結果は出るようになりました。
    ですが、正規表現でなんとかしたいと思っております。

    キャンセル

  • 2017/11/23 17:06

    横からですが正規表現にこだわる理由が知りたいと思いました。

    キャンセル

  • 2017/11/23 17:07

    ちょうどsuyamaさんが正規表現による回答を書いてくださったので、そちらをご覧ください。

    キャンセル

  • 2017/11/23 17:16

    ちょっと気になって本家の実装を見てみました。
    思ったよりゴリゴリ書いていて面白かったので、やっぱり回答にはなっていませんが追記しておきました。

    キャンセル

  • 2017/11/24 08:08

    wakame様
    お世話になっております。
    正規表現を勉強しており、せっかくなら正規表現で解決したいと思った次第です。

    キャンセル

  • 2017/11/27 13:20

    外した回答でBAいただいてしまったので、ちょっと追記しました。
    正規表現に苦手意識がある(というか体系的に学んでいない)ので間違ったこと書いていないかちょっと不安だったりします。

    キャンセル

  • 2017/11/27 22:30

    LouiS0616さん
    ありがとうございます。
    詳細に教えていただき、関数まで作っていただいたのでBAとさせていただきました。
    正規表現の場合、$で行末を指定することでできました。

    キャンセル

+2

IPv4アドレスにマッチする文字列を抽出する正規表現は下記となるようです。

(([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])

IPアドレスのフォーマットチェック(正規表現) | IPラーニング
http://www.geolocation.co.jp/learn/program/07.html

IPv6アドレスの場合についても、参考までリンクします。

IPv6アドレスをより妥当な正規表現でマッチする。 - 設計と実装の狭間で。
http://d.hatena.ne.jp/taichitaichi/20110112/1294819517

投稿 2017/11/23 17:04

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/27 12:05

    suyamaさん
    ありがとうございました。本URLを参考にさせていただきます。

    キャンセル

  • 2017/11/27 12:12

    すぐ手元に本がないのでうろ覚えですが、正規表現ハンドブックという本に色々なパターンにマッチさせるための正規表現が収録されていたと思います。ご参考までに。
    http://www.sbcr.jp/products/4797328509.html

    キャンセル

  • 2017/11/27 22:33

    suyamaさん
    情報ありがとうございます。
    参考にさせていただきます。

    キャンセル

+2

from ipaddress import IPv4Address
from itertools import repeat
from re import compile
from random import randint

ipv4 = compile(r'\.'.join(repeat(
    r'(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])', 4)))

for _ in range(100000):
    address = str(IPv4Address(randint(0, 0xFFFFFFFF)))
    assert ipv4.match(address), address

address = "1.2.3.4"
m = ipv4.match(address)
if m:
    print("Ture")
else:
    print("False")

投稿 2017/11/25 01:07

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/27 12:10

    YouheiSakuraiさん
    ご回答ありがとうございました。解決できそうです。
    コード内容を詳しく拝見させていただきます。

    キャンセル

+1

 RFC3986

RFC3986 では ABNF 形式で IPv4address 書式を定義しているので、参考にすると良いと思います。

昔、JavaScriptで正規表現に書き起こしたことがあります。

var DIGIT  = '[\u0030-\u0039]',              // [0-9]
    dec_octet   = '(?:' + DIGIT + '|[\u0031-\u0039]' + DIGIT + '|1(?:' + DIGIT + '){2}|2[\u0030-\u0034]' + DIGIT + '|25[\u0030-\u0035]),
    IPv4address = dec_octet + '\\.' + dec_octet + '\\.' + dec_octet + '\\.' + dec_octet;

console.log(IPv4address); // (?:[0-9]|[1-9][0-9]|1(?:[0-9]){2}|2[0-4][0-9]|25[0-5])\.(?:[0-9]|[1-9][0-9]|1(?:[0-9]){2}|2[0-4][0-9]|25[0-5])\.(?:[0-9]|[1-9][0-9]|1(?:[0-9]){2}|2[0-4][0-9]|25[0-5])\.(?:[0-9]|[1-9][0-9]|1(?:[0-9]){2}|2[0-4][0-9]|25[0-5])

ところで、IPv6には対応しなくていいのでしょうか。
(githubのコードに IPv6address のコードもあります)

Re: yuyu127 さん

投稿 2017/11/26 22:17

編集 2017/11/26 22:27

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/27 12:04

    think49さん
    ご回答ありがとうございました。
    正規表現を勉強していて出てきた課題でしたが、IPv6も考えてみたいと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.37%

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    2398questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 正規表現

    566questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。