Регулярное выражение, соответствующее действительным адресам IPv6

111

У меня проблемы с написанием регулярного выражения, которое соответствует действительным IPv6-адресам, в том числе в их сжатой форме (с ::опущенными в каждой паре байтов ведущими нулями).

Может ли кто-нибудь предложить регулярное выражение, которое удовлетворяет требованию?

Я рассматриваю возможность расширения каждой пары байтов и сопоставления результата с более простым регулярным выражением.

Только чтение
источник
1
Зайдите
Я пробовал все ответы ниже, и они не работают для всех моих тестовых случаев и / или они также включают IPv4, о котором не просили. Я считаю, что это самое чистое решение на данный момент: stackoverflow.com/a/21944928/3112803
gfrobenius

Ответы:

252

Мне не удалось получить ответ @Factor Mystic для работы с регулярными выражениями POSIX, поэтому я написал тот, который работает с регулярными выражениями POSIX и регулярными выражениями PERL.

Он должен соответствовать:

Регулярное выражение IPv6:

(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))

Для удобства чтения следующее регулярное выражение разделено по основным точкам ИЛИ на отдельные строки:

# IPv6 RegEx
(
([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|          # 1:2:3:4:5:6:7:8
([0-9a-fA-F]{1,4}:){1,7}:|                         # 1::                              1:2:3:4:5:6:7::
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|         # 1::8             1:2:3:4:5:6::8  1:2:3:4:5:6::8
([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|  # 1::7:8           1:2:3:4:5::7:8  1:2:3:4:5::8
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|  # 1::6:7:8         1:2:3:4::6:7:8  1:2:3:4::8
([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|  # 1::5:6:7:8       1:2:3::5:6:7:8  1:2:3::8
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|  # 1::4:5:6:7:8     1:2::4:5:6:7:8  1:2::8
[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|       # 1::3:4:5:6:7:8   1::3:4:5:6:7:8  1::8  
:((:[0-9a-fA-F]{1,4}){1,7}|:)|                     # ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8 ::8       ::     
fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|     # fe80::7:8%eth0   fe80::7:8%1     (link-local IPv6 addresses with zone index)
::(ffff(:0{1,4}){0,1}:){0,1}
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|          # ::255.255.255.255   ::ffff:255.255.255.255  ::ffff:0:255.255.255.255  (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
([0-9a-fA-F]{1,4}:){1,4}:
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])           # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
)

# IPv4 RegEx
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])

Чтобы упростить понимание вышеизложенного, следующий «псевдокод» повторяет приведенное выше:

IPV4SEG  = (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])
IPV4ADDR = (IPV4SEG\.){3,3}IPV4SEG
IPV6SEG  = [0-9a-fA-F]{1,4}
IPV6ADDR = (
           (IPV6SEG:){7,7}IPV6SEG|                # 1:2:3:4:5:6:7:8
           (IPV6SEG:){1,7}:|                      # 1::                                 1:2:3:4:5:6:7::
           (IPV6SEG:){1,6}:IPV6SEG|               # 1::8               1:2:3:4:5:6::8   1:2:3:4:5:6::8
           (IPV6SEG:){1,5}(:IPV6SEG){1,2}|        # 1::7:8             1:2:3:4:5::7:8   1:2:3:4:5::8
           (IPV6SEG:){1,4}(:IPV6SEG){1,3}|        # 1::6:7:8           1:2:3:4::6:7:8   1:2:3:4::8
           (IPV6SEG:){1,3}(:IPV6SEG){1,4}|        # 1::5:6:7:8         1:2:3::5:6:7:8   1:2:3::8
           (IPV6SEG:){1,2}(:IPV6SEG){1,5}|        # 1::4:5:6:7:8       1:2::4:5:6:7:8   1:2::8
           IPV6SEG:((:IPV6SEG){1,6})|             # 1::3:4:5:6:7:8     1::3:4:5:6:7:8   1::8
           :((:IPV6SEG){1,7}|:)|                  # ::2:3:4:5:6:7:8    ::2:3:4:5:6:7:8  ::8       ::       
           fe80:(:IPV6SEG){0,4}%[0-9a-zA-Z]{1,}|  # fe80::7:8%eth0     fe80::7:8%1  (link-local IPv6 addresses with zone index)
           ::(ffff(:0{1,4}){0,1}:){0,1}IPV4ADDR|  # ::255.255.255.255  ::ffff:255.255.255.255  ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
           (IPV6SEG:){1,4}:IPV4ADDR               # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
           )

Я разместил на GitHub скрипт, который проверяет регулярное выражение: https://gist.github.com/syzdek/6086792

Дэвид М. Сыздек
источник
3
127.000.000.001
Регулярное
21
Сегменты IPv4 не должны включать начальные нули. Если присутствует начальный ноль, сегмент IPv4 следует интерпретировать в восьмеричном формате. Таким образом, приведенный выше IPV4SEG правильно не допускает "000". Однако он разрешает «00», чего не должен.
номинал
3
У меня не сработало в браузере, как я ожидал. Проверено даже reg.test ('3zzzzffe: 1900: 4545: 3: 200: f8ff: fe21: 67cf'), который, очевидно, не является действительным адресом IPv6. Здесь были гораздо лучшие результаты с регулярным выражением: nbviewer.ipython.org/github/rasbt/python_reference/blob/master/…
Capaj
7
фантастическое регулярное выражение ipv6. нашел небольшую ошибку со ссылкой локальный раздел. у вас fe80там должно быть что-то вроде [fF][eE]80и ffffчто должно быть что-то вроде[fF]{4}
user2831628
4
+1 для демонстрации того, что регулярные выражения могут быть (как и любой исходный код) действительно читаемыми, если вы позаботитесь и отформатируете их.
Natix
52

Следующее будет проверять адреса IPv4, IPv6 (полные и сжатые) и IPv6v4 (полные и сжатые):

'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD'
MichaelRushton
источник
8
Несмотря на то, что проверка IP-адресов может быть выполнена, как предлагает Фрэнк Крюгер, это решение является тем, которое действительно отвечает на вопрос (хотя я еще не полностью его тестировал), а также если у вас много IP-адресов, которые вы хотите синтаксически протестировать. и, возможно, соответствует строке текста, вы не можете использовать метод проверки IP.
Гюри
Привет, я тестировал этот RegExp и не работал у меня. Он говорит, что D является недопустимым флагом, и когда я его удаляю, он говорит: «SyntaxError: недопустимый квантификатор»
Диосней
3
JavaScript реализует подмножество регулярных выражений в стиле Perl, а не весь PCRE. Мое регулярное выражение не будет работать без некоторых дополнительных функций PCRE.
MichaelRushton
2
Это дает мне исключение в C #
sarat
1
Неудачный тестовый пример: FE80: 0000: 0000: 0000: 0202: B3FF: FE1E: 8329 Используется последняя версия Elixir на эту дату, которая использует PCRE внизу.
pmarreck
23

Похоже, вы используете Python. Если это так, вы можете использовать что-то вроде этого:

import socket

def check_ipv6(n):
    try:
        socket.inet_pton(socket.AF_INET6, n)
        return True
    except socket.error:
        return False

print check_ipv6('::1') # True
print check_ipv6('foo') # False
print check_ipv6(5)     # TypeError exception
print check_ipv6(None)  # TypeError exception

Я не думаю, что вам нужно иметь IPv6, скомпилированный в Python, чтобы получить inet_pton, который также может анализировать адреса IPv4, если вы передадите его в socket.AF_INETкачестве первого параметра. Примечание: это может не работать в системах, отличных от Unix.

Джо Хильдебранд
источник
4
В предложении следует указать тип исключения except. Иначе exceptвсе поймают и могут замаскировать не связанные ошибки. Тип здесь должен быть socket.error.
Ayman Hourieh,
A) inet_pton не генерирует других исключений, если только документы не являются неправильными, и B) даже если это так, что еще вы бы вернули, кроме False?
Джо Хильдебранд,
2
Re: другие ошибки ... если пользователь передает не-строку, TypeError съедается. Ясно, что список не является ipv6, но я, вероятно, хотел бы, чтобы он придрался к тому, что я передал неправильный тип.
Грегг Линд
1
+1 Это мне очень помогло. Следует добавить пару дополнительных моментов: 1) socket.inet_pton может использоваться для проверки правильности обоих семейств IP-адресов (IP и IPv6). 2) Документы здесь ( docs.python.org/2/library/socket.html ) предполагают, что это доступно на платформах Unix. Это может быть недоступно на Win-платформах.
mkoistinen 05
используя django, и это помогает!
elad silver
23

Из " регулярного выражения IPv6 ":

(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}\Z)|
(\A([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}\Z)|
(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|
(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|
(\A:(:[0-9a-f]{1,4}){1,7}\Z)|
(\A((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)
Фактор Мистик
источник
45
Подобное регулярное выражение должно быть «запахом кода»; возможно, регулярное выражение здесь не лучшее решение. (Хотя, я думаю, оператор действительно просил об этом ...)
Танатос
10
@ user712092 - все, кто видел базу кода с такими бельями на глазу,
danielpops
2
Это совершенно ненужная пародия на RE. Программа, создавшая его, не понимала, что делает. Человек никогда бы так не поступил. Пусть вас не вводит в заблуждение кажущаяся сложность - RE действительно являются «черной магией» для многих людей, но нет причин размещать их на другой планете!
Чак Колларс
+1, но OMG должен быть лучший способ сделать это: P Для справки: для Rails это может помочь: stackoverflow.com/questions/16965697/…
Tilo
1
Это действительно запах кода; однако, посмотрев, вы увидите, что каждое регулярное выражение довольно лаконично. Проблема в том, что существуют разные шаблоны, созданные `` сжатием '' ipv6 - начало, середина и конец двоеточия, кроме того, если вы использовали двойное двоеточие, вы не можете использовать его снова, помимо всего двоеточия до и после двойного суммирования. Perl 6 может с этим справиться, но это выходит далеко за рамки синтаксиса PCRE. (PS - Я не считаю встроенный ipv4 в конце, он длиннее, чем раздел ipv6!)
Джерард
11

Я должен был бы полностью поддержать ответ Фрэнка Крюгера .

Хотя вы говорите, что вам нужно регулярное выражение для соответствия IPv6-адресу, я предполагаю, что вам действительно нужно иметь возможность проверить, является ли данная строка действительным IPv6-адресом. Здесь есть тонкое, но важное различие.

Существует несколько способов проверить, является ли данная строка допустимым адресом IPv6, и сопоставление регулярных выражений - только одно из решений.

По возможности используйте существующую библиотеку. В библиотеке будет меньше ошибок, и ее использование приведет к меньшему количеству кода, который вам придется поддерживать.

Регулярное выражение, предложенное Factor Mystic , длинное и сложное. Скорее всего, это сработает, но вам также следует подумать, как вы справитесь, если он неожиданно выйдет из строя. Я пытаюсь подчеркнуть, что если вы не можете самостоятельно сформировать требуемое регулярное выражение, вы не сможете легко отладить его.

Если у вас нет подходящей библиотеки, возможно, лучше написать собственную процедуру проверки IPv6, которая не зависит от регулярных выражений. Если вы пишете это, вы понимаете это, и если вы понимаете это, вы можете добавлять комментарии, чтобы объяснить это, чтобы другие могли также понять и впоследствии поддерживать его.

Будьте осторожны при использовании регулярных выражений, функции которых вы не можете объяснить кому-либо.

Джон Крам
источник
1
Использование двух регулярных выражений, либерального выражения и выражения исключений для перехвата недопустимых адресов, разрешенных первым, может быть проще, чем одно выражение ( return ex1.match(S) && ! ex2.match(S)).
Raedwald 02
4
Вы предполагаете, что он проверяет отдельные IP-адреса, когда почти наверняка ищет IP-адреса в большом блоке текста.
Navin
8

Я не эксперт по IPv6, но думаю, что вы можете легко получить довольно хороший результат с этим:

^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$

чтобы ответить "это действительный ipv6", мне кажется, что это нормально. Чтобы разбить это на части ... забудьте об этом. Я пропустил неуказанный (: :), так как в моей базе данных нет смысла иметь «неуказанный адрес».

начало: ^([0-9A-Fa-f]{0,4}:){2,7}<- соответствует сжимаемой части, мы можем перевести это как: от 2 до 7 двоеточие, между которыми может быть шестнадцатеричное число.

за которым следует: [0-9A-Fa-f]{1,4}$<- шестнадцатеричное число (ведущий 0 опущен) ИЛИ ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}<- адрес IPv4

Реми Морин
источник
1
+1 за то, что на самом деле придерживались вопроса OP и представляли относительно красивое регулярное выражение, которое несколько работает.
xebeche
1
Это не соответствует ":: 1"
lsalamon
А? В синтаксисе регулярных выражений Java это действительно совпадает:start() = 0, end() = 3 group(0) = "::1" group(1) = ":" group(2) = "1" group(3) = "null" group(4) = "null" group(5) = "null"
Реми Морин
Где-то еще кто-то уведомил меня о проблеме с моим регулярным выражением, сжатая часть "::" может появиться только один раз. Таким образом, ":: 1 :: 2" будет соответствовать моему регулярному выражению, но это неверный IPV6. Второе регулярное выражение может проверить этот случай. Полная рекомендация заключалась в использовании парсера с отслеживанием состояния для проверки. Я согласен с тем, что полученный код будет легче читать и поддерживать (и кто-то, вероятно, уже где-то закодировал его в открытом доступе).
Реми Морин
8

Это также улавливает loopback (:: 1) и адреса ipv6. изменил {} на + и поместил: внутри первой квадратной скобки.

([a-f0-9:]+:+)+[a-f0-9]+

протестировано с помощью ifconfig -a output http://regexr.com/

Параметр o терминала Unix или Mac OSx возвращает только соответствующий вывод (ipv6), включая :: 1

ifconfig -a | egrep -o '([a-f0-9:]+:+)+[a-f0-9]+'

Получить все IP-адреса (IPv4 ИЛИ IPv6) и распечатать совпадение по термину unix OSx

ifconfig -a | egrep -o '([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) | (([a-f0-9:]+:+)+[a-f0-9]+)'
Рохит Малгаонкар
источник
Мне нравится простота. В конечном итоге это сработало для меня:ip a | grep -Po '[\w:]+:+[\w:]+'
Ноам Манос
Юмор приветствуется!
Soumya Kanti
Когда я запускаю ipconfig / all, мой IP-адрес заканчивается на% 10, это выражение не соответствует этой части?
Питер
7

Это регулярное выражение будет соответствовать действительным адресам IPv6 и IPv4 в соответствии с реализацией регулярного выражения GNU C ++ с использованием режима REGULAR EXTENDED:

"^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?\s*$"
janCoffee
источник
5

Осторожно! В Java использование InetAddress и связанных классов (Inet4Address, Inet6Address, URL) может включать сетевой трафик! Например, разрешение DNS (URL.equals, InetAddress из строки!). Этот звонок может занять много времени и блокируется!

Для IPv6 у меня примерно так. Это, конечно, не обрабатывает очень тонкие детали IPv6, например, что индексы зон разрешены только для некоторых классов адресов IPv6. И это регулярное выражение не написано для группового захвата, это просто регулярное выражение "совпадения".

S - Сегмент IPv6 = [0-9a-f]{1,4}

I - IPv4 = (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})

Схема (первая часть соответствует адресам IPv6 с суффиксом IPv4, вторая часть соответствует адресам IPv6, последняя часть соответствует индексу зоны):

(
(
::(S:){0,5}|
S::(S:){0,4}|
(S:){2}:(S:){0,3}|
(S:){3}:(S:){0,2}|
(S:){4}:(S:)?|
(S:){5}:|
(S:){6}
)
I

|

:(:|(:S){1,7})|
S:(:|(:S){1,6})|
(S:){2}(:|(:S){1,5})|
(S:){3}(:|(:S){1,4})|
(S:){4}(:|(:S){1,3})|
(S:){5}(:|(:S){1,2})|
(S:){6}(:|(:S))|
(S:){7}:|
(S:){7}S
)

(?:%[0-9a-z]+)?

И здесь может быть регулярное выражение (без учета регистра, окружение тем, что когда-либо было необходимо, например, начало / конец строки и т. Д.):

(?:
(?:
::(?:[0-9a-f]{1,4}:){0,5}|
[0-9a-f]{1,4}::(?:[0-9a-f]{1,4}:){0,4}|
(?:[0-9a-f]{1,4}:){2}:(?:[0-9a-f]{1,4}:){0,3}|
(?:[0-9a-f]{1,4}:){3}:(?:[0-9a-f]{1,4}:){0,2}|
(?:[0-9a-f]{1,4}:){4}:(?:[0-9a-f]{1,4}:)?|
(?:[0-9a-f]{1,4}:){5}:|
(?:[0-9a-f]{1,4}:){6}
)
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})|

:(?::|(?::[0-9a-f]{1,4}){1,7})|
[0-9a-f]{1,4}:(?::|(?::[0-9a-f]{1,4}){1,6})|
(?:[0-9a-f]{1,4}:){2}(?::|(?::[0-9a-f]{1,4}){1,5})|
(?:[0-9a-f]{1,4}:){3}(?::|(?::[0-9a-f]{1,4}){1,4})|
(?:[0-9a-f]{1,4}:){4}(?::|(?::[0-9a-f]{1,4}){1,3})|
(?:[0-9a-f]{1,4}:){5}(?::|(?::[0-9a-f]{1,4}){1,2})|
(?:[0-9a-f]{1,4}:){6}(?::|(?::[0-9a-f]{1,4}))|
(?:[0-9a-f]{1,4}:){7}:|
(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}
)

(?:%[0-9a-z]+)?
user2623580
источник
4

Следующее регулярное выражение предназначено только для IPv6. Группа 1 совпадает с IP.

(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})
Джитендра Госави
источник
+1 Не всегда обязательно иметь идеальное суперсложное регулярное выражение, которое человек не может понять. Я буду использовать этот, потому что я понимаю, что он делает, и в моем случае я могу быть уверен, что если я получу что-то похожее на действительный ipv6, значит, это действительный ipv6.
Дэвид Л.
3
это не совпадет скажем: fe80 :: 1 или 2342: 32fd :: 2d32
Джеймс
3

Простое регулярное выражение, которое будет соответствовать, но я бы не рекомендовал для какой-либо проверки, это следующее:

([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}

Обратите внимание, что это соответствует сжатию в любом месте адреса, но не соответствует адресу обратной связи :: 1. Я считаю это разумным компромиссом для упрощения регулярного выражения.

Я успешно использую это в правилах интеллектуального выбора iTerm2 для четырех щелчков по IPv6-адресам.

Джиннко
источник
3
Вы имели в виду A-F, нет A-Z! Также обратите внимание, что вы исключаете запись с разделением на четыре точки.
xebeche
3

Если вы используете Perl, попробуйте Net :: IPv6Addr

use Net::IPv6Addr;

if( defined Net::IPv6Addr::is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}

NetAddr :: IP

use NetAddr::IP;

my $obj = NetAddr::IP->new6($ip_address);

Проверить :: IP

use Validate::IP qw'is_ipv6';

if( is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}
Брэд Гилберт
источник
Или Data :: Validate :: IP search.cpan.org/~neely/Data-Validate-IP-0.11/lib/Data/Validate/… .
Калимо
2

В Scala используются хорошо известные валидаторы Apache Commons.

http://mvnrepository.com/artifact/commons-validator/commons-validator/1.4.1

libraryDependencies += "commons-validator" % "commons-validator" % "1.4.1"


import org.apache.commons.validator.routines._

/**
 * Validates if the passed ip is a valid IPv4 or IPv6 address.
 *
 * @param ip The IP address to validate.
 * @return True if the passed IP address is valid, false otherwise.
 */  
 def ip(ip: String) = InetAddressValidator.getInstance().isValid(ip)

После проверки метода ip(ip: String):

"The `ip` validator" should {
  "return false if the IPv4 is invalid" in {
    ip("123") must beFalse
    ip("255.255.255.256") must beFalse
    ip("127.1") must beFalse
    ip("30.168.1.255.1") must beFalse
    ip("-1.2.3.4") must beFalse
  }

  "return true if the IPv4 is valid" in {
    ip("255.255.255.255") must beTrue
    ip("127.0.0.1") must beTrue
    ip("0.0.0.0") must beTrue
  }

  //IPv6
  //@see: http://www.ronnutter.com/ipv6-cheatsheet-on-identifying-valid-ipv6-addresses/
  "return false if the IPv6 is invalid" in {
    ip("1200::AB00:1234::2552:7777:1313") must beFalse
  }

  "return true if the IPv6 is valid" in {
    ip("1200:0000:AB00:1234:0000:2552:7777:1313") must beTrue
    ip("21DA:D3:0:2F3B:2AA:FF:FE28:9C5A") must beTrue
  }
}
ОливерКК
источник
Интересно, что он утверждает, что проверяет, что это действительный адрес, « Проверяет, является ли переданный IP действительным адресом IPv4 или IPv6. », Но на самом деле проверяет только то, что он отформатирован как действительный адрес. Например, 1200:0000:AB00:1234:0000:2552:7777:1313это допустимый формат для IPv6-адреса, но он не является действительным IPv6-адресом, как возвращает тестовый метод. Готов поспорить, он думает, что 241.54.113.65это действительный адрес IPv4.
Рон Мопин
2

Глядя на шаблоны, включенные в другие ответы, можно выделить ряд хороших шаблонов, которые можно улучшить, ссылаясь на группы и используя опережающие просмотры. Вот пример шаблона, который ссылается на себя, который я бы использовал в PHP, если бы мне пришлось:

^(?<hgroup>(?<hex>[[:xdigit:]]{0,4}) # grab a sequence of up to 4 hex digits
                                     # and name this pattern for usage later
     (?<!:::):{1,2})                 # match 1 or 2 ':' characters
                                     # as long as we can't match 3
 (?&hgroup){1,6} # match our hex group 1 to 6 more times
 (?:(?:
    # match an ipv4 address or
    (?<dgroup>2[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(?&dgroup)
    # match our hex group one last time
    |(?&hex))$

Примечание: PHP имеет встроенный фильтр для этого, что было бы лучшим решением, чем этот шаблон.

Regex101 Анализ

Стив Бузонас
источник
2

Я сгенерировал следующее, используя python и работаю с модулем re. Утверждения упреждающего просмотра обеспечивают правильное количество точек или двоеточий в адресе. Он не поддерживает IPv4 в нотации IPv6.

pattern = '^(?=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)(?:(?:25[0-5]|[12][0-4][0-9]|1[5-9][0-9]|[1-9]?[0-9])\.?){4}$|(?=^(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$)(?![^:]*::.+::[^:]*$)(?:(?=.*::.*)|(?=\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+))(?:(?:^|:)(?:[0-9a-f]{4}|[1-9a-f][0-9a-f]{0,3})){0,8}(?:::(?:[0-9a-f]{1,4}(?:$|:)){0,6})?$'
result = re.match(pattern, ip)
if result: result.group(0)
Майк Уилмс
источник
2

Регулярные выражения для ipv6 могут быть очень сложными, если учесть адреса со встроенным ipv4 и сжатые адреса, как вы можете видеть из некоторых из этих ответов.

Библиотека IPAddress Java с открытым исходным кодом будет проверять все стандартные представления IPv6 и IPv4, а также поддерживает длину префикса (и ее проверку). Отказ от ответственности: я являюсь руководителем проекта этой библиотеки.

Пример кода:

        try {
            IPAddressString str = new IPAddressString("::1");
            IPAddress addr = str.toAddress();
            if(addr.isIPv6() || addr.isIPv6Convertible()) {
                IPv6Address ipv6Addr = addr.toIPv6();
            }
            //use address
        } catch(AddressStringException e) {
            //e.getMessage has validation error
        }
Шон Ф
источник
1

В Java вы можете использовать класс библиотеки sun.net.util.IPAddressUtil:

IPAddressUtil.isIPv6LiteralAddress(iPaddress);
пользователь463639
источник
3
sun.net. * - это частный API.
Дэвид Кочер
1

Трудно найти регулярное выражение, которое работало бы для всех случаев IPv6. Обычно их сложно поддерживать, их нелегко читать и они могут вызвать проблемы с производительностью. Следовательно, я хочу поделиться альтернативным решением, которое я разработал: Регулярное выражение (RegEx) для IPv6 Отдельно от IPv4

Теперь вы можете спросить: «Этот метод находит только IPv6, как я могу найти IPv6 в тексте или файле?» Вот способы решения этой проблемы.

Примечание . Если вы не хотите использовать класс IPAddress в .NET, вы также можете заменить его моим методом . Он также охватывает сопоставленный IPv4 и особые случаи, в то время как IPAddress не распространяется.

class IPv6
{
    public List<string> FindIPv6InFile(string filePath)
    {
        Char ch;
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();
        StreamReader reader = new StreamReader(filePath);
        do
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                ch = (char)reader.Read();

                if (IsEscapeChar(ch))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (ch == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(ch.ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(ch.ToString());
                }

                length++;

            } while (!reader.EndOfStream);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            sbIPv6.Clear();

        } while (!reader.EndOfStream);
        reader.Close();
        reader.Dispose();

        return listIPv6;
    }

    public List<string> FindIPv6InText(string text)
    {
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();

        for (int i = 0; i < text.Length; i++)
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                if (IsEscapeChar(text[length + i]))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (text[length + i] == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(text[length + i].ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(text[length + i].ToString());
                }

                length++;

            } while (i + length != text.Length);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            i += length;
            sbIPv6.Clear();
        }

        return listIPv6;
    }

    bool IsEscapeChar(char ch)
    {
        if (ch != ' ' && ch != '\r' && ch != '\n' && ch!='\t')
        {
            return false;
        }

        return true;
    }

    bool IsIPv6(string maybeIPv6)
    {
        IPAddress ip;
        if (IPAddress.TryParse(maybeIPv6, out ip))
        {
            return ip.AddressFamily == AddressFamily.InterNetworkV6;
        }
        else
        {
            return false;
        }
    }

}
Нух Метин Гюлер
источник
1

InetAddressUtilsвсе шаблоны определены. В итоге я использовал их шаблон напрямую и вставляю его сюда для справки:

private static final String IPV4_BASIC_PATTERN_STRING =
        "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
         "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255

private static final Pattern IPV4_PATTERN =
    Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
        Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV6_STD_PATTERN =
    Pattern.compile(
            "^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");

private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
    Pattern.compile(
            "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
             "::" +
             "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields 
user4604205
источник
1

Используете Ruby? Попробуй это:

/^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/i
Ахамкс
источник
1

В зависимости от ваших потребностей приблизительное значение, например:

[0-9a-f:]+

может быть достаточно (например, с помощью простого поиска в файле журнала).

Билл Липа
источник
0

Для пользователей PHP 5.2+ filter_varотлично работает.

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

$is_ip4address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE);
$is_ip6address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== FALSE);
Wireblue
источник
0

Это будет работать для IPv4 и IPv6:

^(([0-9a-f]{0,4}:){1,7}[0-9a-f]{1,4}|([0-9]{1,3}\.){3}[0-9]{1,3})$
Крис
источник
2
Он сопоставляет недопустимые адреса с двумя экземплярами ::. например2404:6800::4003:c02::8a
nhahtdh 03
совпадает с недопустимым IPv4 666.666.666.666
Райан Уильямс
0

Вот что я придумал, используя немного предвидения и именованные группы. Это, конечно, просто IPv6, но он не должен мешать дополнительным шаблонам, если вы хотите добавить IPv4:

(?=([0-9a-f]+(:[0-9a-f])*)?(?P<wild>::)(?!([0-9a-f]+:)*:))(::)?([0-9a-f]{1,4}:{1,2}){0,6}(?(wild)[0-9a-f]{0,4}|[0-9a-f]{1,4}:[0-9a-f]{1,4})
user1977022
источник
0

Просто сопоставление локальных из источника с включенными квадратными скобками. Я знаю, что это не так полно, но в javascript другим было трудно отследить проблемы, в первую очередь неработающие, так что, похоже, это дает мне то, что мне нужно сейчас. лишние заглавные буквы AF тоже не нужны.

^\[([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})\]

Версия Джиннко упрощена и я вижу лучше.

Мастер Джеймс
источник
0

Как уже говорилось выше, еще один способ , чтобы получить текстовое представление IPv6 проверки парсер использовать программирование. Вот тот, который полностью соответствует RFC-4291 и RFC-5952. Я написал этот код на ANSI C (работает с GCC, прошел тесты на Linux - работает с clang, прошел тесты на FreeBSD). Таким образом, он полагается только на стандартную библиотеку ANSI C, поэтому его можно компилировать везде (я использовал его для синтаксического анализа IPv6 внутри модуля ядра с FreeBSD).

// IPv6 textual representation validating parser fully compliant with RFC-4291 and RFC-5952
// BSD-licensed / Copyright 2015-2017 Alexandre Fenyo

#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

typedef enum { false, true } bool;

static const char hexdigits[] = "0123456789abcdef";
static int digit2int(const char digit) {
  return strchr(hexdigits, digit) - hexdigits;
}

// This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
// Other representations will return -1.
//
// note that str input parameter has been modified when the function call returns
//
// parse_ipv6(char *str, struct in6_addr *retaddr)
// parse textual representation of IPv6 addresses
// str:     input arg
// retaddr: output arg
int parse_ipv6(char *str, struct in6_addr *retaddr) {
  bool compressed_field_found = false;
  unsigned char *_retaddr = (unsigned char *) retaddr;
  char *_str = str;
  char *delim;

  bzero((void *) retaddr, sizeof(struct in6_addr));
  if (!strlen(str) || strchr(str, ':') == NULL || (str[0] == ':' && str[1] != ':') ||
      (strlen(str) >= 2 && str[strlen(str) - 1] == ':' && str[strlen(str) - 2] != ':')) return -1;

  // convert transitional to standard textual representation
  if (strchr(str, '.')) {
    int ipv4bytes[4];
    char *curp = strrchr(str, ':');
    if (curp == NULL) return -1;
    char *_curp = ++curp;
    int i;
    for (i = 0; i < 4; i++) {
      char *nextsep = strchr(_curp, '.');
      if (_curp[0] == '0' || (i < 3 && nextsep == NULL) || (i == 3 && nextsep != NULL)) return -1;
      if (nextsep != NULL) *nextsep = 0;
      int j;
      for (j = 0; j < strlen(_curp); j++) if (_curp[j] < '0' || _curp[j] > '9') return -1;
      if (strlen(_curp) > 3) return -1;
      const long val = strtol(_curp, NULL, 10);
      if (val < 0 || val > 255) return -1;
      ipv4bytes[i] = val;
      _curp = nextsep + 1;
    }
    sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
  }

  // parse standard textual representation
  do {
    if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
      if (delim == str) _str++;
      else if (delim == NULL) return 0;
      else {
        if (compressed_field_found == true) return -1;
        if (delim == str + strlen(str) - 1 && _retaddr != (unsigned char *) (retaddr + 1)) return 0;
        compressed_field_found = true;
        _str++;
        int cnt = 0;
        char *__str;
        for (__str = _str; *__str; ) if (*(__str++) == ':') cnt++;
        unsigned char *__retaddr = - 2 * ++cnt + (unsigned char *) (retaddr + 1);
        if (__retaddr <= _retaddr) return -1;
        _retaddr = __retaddr;
      }
    } else {
      char hexnum[4] = "0000";
      if (delim == NULL) delim = str + strlen(str);
      if (delim - _str > 4) return -1;
      int i;
      for (i = 0; i < delim - _str; i++)
        if (!isxdigit(_str[i])) return -1;
        else hexnum[4 - (delim - _str) + i] = tolower(_str[i]);
      _str = delim + 1;
      *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
      *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
    }
  } while (_str < str + strlen(str));
  return 0;
}
Александр Феньо
источник
-1

Попробуйте этот небольшой однострочник. Он должен соответствовать только действительным несжатым / сжатым адресам IPv6 (без гибридов IPv4)

/(?!.*::.*::)(?!.*:::.*)(?!:[a-f0-9])((([a-f0-9]{1,4})?[:](?!:)){7}|(?=(.*:[:a-f0-9]{1,4}::|^([:a-f0-9]{1,4})?::))(([a-f0-9]{1,4})?[:]{1,2}){1,6})[a-f0-9]{1,4}/
Карлос Веласкес
источник
Фактически, допустимые адреса IPv6 включают несжатые, сжатые, несжатые гибридные и сжатые гибридные. На самом деле для сопоставления любого действительного текстового представления IPv6-адреса требуется гораздо больше, чем нужно.
Рон Мопин
-2

Регулярное выражение позволяет использовать ведущие нули в частях IPv4.

Некоторые дистрибутивы Unix и Mac преобразуют эти сегменты в восьмеричные числа.

Предлагаю использовать 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\dкак сегмент IPv4.

Aeron
источник
-2

Если вам нужны только обычные IP-адреса (без косой черты), вот:

^(?:[0-9a-f]{1,4}(?:::)?){0,7}::[0-9a-f]+$

Я использую его для подсветки синтаксиса в приложении для редактирования файлов hosts. Работает как оберег.

Гарри
источник
Ни в коем случае, чтобы это когда-либо работало прилично, он не может сопоставить один адрес ipv6 с одним двоеточием в нем, все ваши совпадения находятся в двойных двоеточиях, и вам явно требуется двойное двоеточие для вашей последней группы, суммирование может происходить где угодно .. ...
KillianDS
(?: [0-9a-f] {1,4} (? :::?)?) {0,7} ::? [0-9a-f] {1,4}
Гарри
По-прежнему неверно, но даже в этом случае вы в конечном итоге будете повторять ответ JinnKo, который достаточно хорош для простых целей, но все же имеет недостатки (не улавливает двойное суммирование и не допускает четырехугольники с точками, ни localhost, ни :: termination,. ..)
KillianDS