регулярное выражение в python - как понять эту таблицу без скобок - PullRequest
2 голосов
/ 19 марта 2020

У меня есть этот код, чтобы проверить, является ли строка действительным адресом IPv4:

import re

def is_ip4(IP):
    label = "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
    pattern = re.compile("(" + label + "\.){3}" + label + "$")
    if pattern.match(IP):
        print("matched!")
    else:
        print("No!")

все работает нормально. но если я уберу скобки с метки, как это

import re

def is_ip4(IP):
    label = "[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
    pattern = re.compile("(" + label + "\.){3}" + label + "$")
    if pattern.match(IP):
        print("matched!")
    else:
        print("No!")

, то будет показан действительный ip для "2090.1.11.0", "20.1.11.0", но не для "2.1.11.0". Я на самом деле немного смущен для случаев с против без скобок. Может кто-нибудь объяснить это для меня? спасибо

1 Ответ

1 голос
/ 19 марта 2020

Причина, по которой вам нужны скобки, заключается в том, что вы используете двухэтапный процесс. Сами по себе круглые скобки ничего не делают (кроме захвата в группе). Но вы также делаете это:

pattern = re.compile("(" + label + "\.){3}" + label + "$")

Регулярное выражение label копируется дважды, сначала для трех повторений, а затем для периода. Эта копия хороша (почти), потому что в заявлении она заключена в скобки еще раз. Однако вторая копия находится за пределами скобок, поэтому вы получите регулярное выражение, подобное (упрощенному):

pattern == '(a|ab|abc\.){3}a|ab|abc$'

Это соответствует, если либо (a|ab|abc\.){3}a соответствует, либо ab или abc. С круглыми скобками это будет выглядеть так:

pattern == '((a|ab|abc)\.){3}(a|ab|abc)$'

Итак, хотя скобки кажутся излишними, их нет по двум причинам. Они держат период отдельно от последнего параметра abc и сохраняют окончательный выбор вместе и отдельно от первого бита.

Однако вам не следует делать это в первую очередь. Просто используйте:

from ipaddress import ip_address

def is_ip4(ip):
    try:
        ip_address(ip)
        return True
    except ValueError:
        return False

Установка не требуется, это стандартная библиотека.

Причина, по которой вы получаете совпадение для '2090.1.11.0', заключается в том, что вы сопоставляете это с:

'([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]\\.){3}[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]$'

Сравнивает его с этим:

'([0-9]){3}[0-9]'

Поскольку [0-9] - это первая опция в выражении 'или' в скобках, повторяется три раза, а вторая [0-9] - первая опция в выражении 'или' после {3}.

Обратите внимание, что $, который вы указали, чтобы убедиться, что вся строка совпадает, объединяется с последним параметром 'или', так что здесь ничего не делать.

Попробуйте выполнить приведенное ниже и обратите внимание на идентичное первое совпадение:

import re

print(re.findall('([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]\\.){3}[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]$', '2090.1.11.0'))
print(re.findall('([0-9]){3}[0-9]', '2090.1.11.0'))

(игнорируйте второе совпадение в первой строке, не относящееся к делу)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...