Регулярное выражение для соответствия имени хоста DNS или IP-адресу?

355

У кого-нибудь есть регулярное выражение, которое будет соответствовать любому юридическому имени или IP-адресу DNS?

Легко написать тот, который работает 95% времени, но я надеюсь получить то, что хорошо проверено, чтобы точно соответствовать последним спецификациям RFC для имен хостов DNS.

Теги:
dns

22 ответа

467
Лучший ответ

Вы можете использовать следующие регулярные выражения отдельно или путем объединения их в совместное выражение OR.

ValidIpAddressRegex = "^(([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])$";

ValidHostnameRegex = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";

ValidIpAddressRegex соответствует действительным IP-адресам и действительным именам хостов ValidHostnameRegex. В зависимости от языка, который вы используете, возможно, нужно экранировать с помощью \.


ValidHostnameRegex действует как RFC 1123. Первоначально RFC 952 указывал, что сегменты хоста не могут начинаться с цифры.

http://en.wikipedia.org/wiki/Hostname

Оригинальная спецификация имена хостов в RFC 952, что лейблы не могут с цифрой или с дефисом, и не должен заканчиваться дефисом. Однако последующая спецификация (RFC 1123) разрешенные метки имен хостов с цифрами.

Valid952HostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$";
  • 0
    Ваше регулярное имя хоста довольно хорошее и выглядит так, как будто оно соответствует всему. Вы должны изменить свой ответ, чтобы он не имел двойного экранирования для точек и дефисов, и sz, который делает его похожим на некоторый язык Microsoft.
  • 3
    Здесь: stackoverflow.com/questions/4645126/… - Я объясняю, что имена, начинающиеся с цифры, также считаются действительными. Кроме того, только одна точка является сомнительной проблемой. Было бы здорово получить больше отзывов об этом.
Показать ещё 29 комментариев
60

Регулярное выражение имени хоста smink не учитывает ограничение длины отдельных меток внутри имени хоста. Каждая метка в допустимом имени хоста может иметь длину не более 63 октетов.

ValidHostnameRegex="^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])\
(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$"

Обратите внимание, что обратная косая черта в конце первой строки (см. выше) представляет собой синтаксис оболочки Unix для разделения длинной строки. Это не является частью самого регулярного выражения.

Здесь просто одно регулярное выражение в одной строке:

^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$

Вы также должны отдельно проверить, что общая длина имени хоста не должна превышать 255 символов. Для получения дополнительной информации обратитесь к RFC-952 и RFC-1123.

  • 4
    Отличная схема размещения. Возможно, это зависит от реализации регулярных выражений в языке, но для JS его можно немного откорректировать, чтобы сделать его более коротким, не теряя ничего: /^[az\d]([az\d\-]{0,61}[az\d])?(\.[az\d]([az\d\-]{0,61}[az\d])?)*$/i
31

Для соответствия допустимому IP-адресу используйте следующее регулярное выражение:

(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}

вместо:

([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\.([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])){3}

Объяснение

Многие механизмы регулярных выражений соответствуют первой возможности в последовательности OR. Например, попробуйте следующее регулярное выражение:

10.48.0.200

Test

Проверьте разницу между good vs bad

  • 4
    Не забывайте, что начало ^ и конец $ или что-то вроде 0.0.0.999 или 999.0.0.0 тоже будут совпадать. ;)
  • 1
    yes для проверки правильности строки начинаются ^ и end $, но если вы ищете IP в тексте, не используйте его.
Показать ещё 2 комментария
5

Кажется, я не могу редактировать верхний пост, поэтому я добавлю здесь свой ответ.

Для имени хоста - простой ответ, пример egrep здесь - http://www.linuxinsight.com/how_to_grep_for_ip_addresses_using_the_gnu_egrep_utility.html

egrep '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}'

Хотя случай не учитывает значения, такие как 0 в первом октете, и значения больше 254 (ip addres) или 255 (сетевая маска). Может быть, дополнительная инструкция if поможет.

Что касается имени логического имени DNS, при условии, что вы проверяете только имена интернет-хостов (а не интрасеть), я написал следующее сжатое, сочетание shell/php, но оно должно применяться как любое регулярное выражение.

сначала перейдите на сайт ietf, загрузите и проанализируйте список юридических доменов 1 уровня:

tld=$(curl -s http://data.iana.org/TLD/tlds-alpha-by-domain.txt |  sed 1d  | cut -f1 -d'-' | tr '\n' '|' | sed 's/\(.*\)./\1/')
echo "($tld)"

Это должно дать вам хороший фрагмент кода, который проверяет законность верхнего доменного имени, например .com.org или .ca

Затем добавьте первую часть выражения в соответствии с приведенными здесь рекомендациями - http://www.domainit.com/support/faq.mhtml?category=Domain_FAQ&question=9 (любая буквенно-цифровая комбинация и символ "-", тире не должно быть в начале или конце октета.

(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+

Затем переместите все вместе (пример PHP preg_match):

$pattern = '/^(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+(AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|YE|YT|YU|ZA|ZM|ZW)[.]?$/i';

    if (preg_match, $pattern, $matching_string){
    ... do stuff
    }

Вы также можете добавить оператор if, чтобы проверить, что строка, которую вы проверяете, короче 256 символов - http://www.ops.ietf.org/lists/namedroppers/namedroppers.2003/msg00964.html

  • 1
    -1, потому что это соответствует фиктивным IP-адресам, таким как «999.999.999.999».
  • 1
    «Хотя в этом случае не учитываются такие значения, как 0 в первом октете, и значения, превышающие 254 (IP-адрес) или 255 (маска сети)».
Показать ещё 1 комментарий
2
def isValidHostname(hostname):

    if len(hostname) > 255:
        return False
    if hostname[-1:] == ".":
        hostname = hostname[:-1]   # strip exactly one dot from the right,
                                   #  if present
    allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
    return all(allowed.match(x) for x in hostname.split("."))
  • 0
    Не могли бы вы объяснить это регулярное выражение? Что именно (?! -), (? <! -) означает?
  • 1
    @Scit, они уверены, что он не начинается и не заканчивается символом «-», если ваш движок регулярных выражений позволяет их использовать. Например, из Python или из Perl .
1

Стоит отметить, что для большинства языков есть библиотеки, которые делают это для вас, часто встроенные в стандартную библиотеку. И эти библиотеки, скорее всего, будут обновляться намного чаще, чем код, который вы скопировали с ответа на переполнение стека четыре года назад и забыли. И, конечно же, они также будут в целом анализировать адрес в какой-то полезной форме, а не просто давать вам матч с группой групп.

Например, обнаружение и разбор IPv4 в (POSIX) C:

#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  for (int i=1; i!=argc; ++i) {
    struct in_addr addr = {0};
    printf("%s: ", argv[i]);
    if (inet_pton(AF_INET, argv[i], &addr) != 1)
      printf("invalid\n");
    else
      printf("%u\n", addr.s_addr);
  }
  return 0;
}

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

Например, в Python:

>>> import ipaddress
>>> import re
>>> msg = "My address is 192.168.0.42; 192.168.0.420 is not an address"
>>> for maybeip in re.findall(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', msg):
...     try:
...         print(ipaddress.ip_address(maybeip))
...     except ValueError:
...         pass
1

Это работает для действительных IP-адресов:

regex = '^([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])$'
1
"^((\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])\.){3}(\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])$"
1
/^(?:[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])(?:\.[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])?$/

localhost же есть

1

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

^(([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))\.){3}([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))$
  • 3
    Вы на самом деле читали вопрос?
0
>>> my_hostname = "testhostn.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True
>>> my_hostname = "testhostn....ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
False
>>> my_hostname = "testhostn.A.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True
0

Что касается IP-адресов, представляется, что есть некоторые дискуссии о том, включать ли ведущие нули. Это когда-то было обычной практикой и принято, поэтому я бы сказал, что они должны быть отмечены как действительные, независимо от текущих предпочтений. Существует также некоторая двусмысленность в отношении того, должен ли текст до и после строки быть проверен, и, опять же, я думаю, что это нужно. 1.2.3.4 является допустимым IP, но 1.2.3.4.5 не является, и ни часть 1.2.3.4, ни часть 2.3.4.5 не должны приводить к совпадению. Некоторые из проблем можно решить с помощью этого выражения:

grep -E '(^|[^[:alnum:]+)(([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.){3}([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])([^[:alnum:]]|$)' 

Несчастная часть здесь заключается в том, что часть регулярных выражений, которая проверяет октет, повторяется, как это верно во многих предлагаемых решениях. Хотя это лучше, чем для экземпляров шаблона, повторение может быть полностью устранено, если подпрограммы поддерживаются в используемом регулярном выражении. Следующий пример позволяет использовать эти функции с помощью переключателя -P grep, а также использовать функции lookahead и lookbehind. (Имя функции, которую я выбрал, является "o" для октета. Я мог бы использовать "октет" в качестве имени, но хотел бы быть кратким.)

grep -P '(?<![\d\w\.])(?<o>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<o>){3}(?![\d\w\.])'

Обработка точки может фактически создавать ложные отрицательные значения, если IP-адреса находятся в файле с текстом в виде предложений, поскольку период может следовать без его частичной пунктирной нотации. Вариант выше будет исправлять:

grep -P '(?<![\d\w\.])(?<x>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<x>){3}(?!([\d\w]|\.\d))'
0

попробуйте следующее:

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

он работает в моем случае.

0
public string GetPublicIP()
    {
        var direction = string.Empty;
        var request = WebRequest.Create("http://checkip.dyndns.org/");

        using (var response = request.GetResponse())
        using (var stream = new StreamReader(response.GetResponseStream()))
        {
            direction = stream.ReadToEnd();
        }

        var matches = matchIp.Match(direction);
        return matches.Captures.Count != 0 ? matches.Captures[0].Value : string.Empty;
    }
0
AddressRegex = "^(ftp|http|https):\/\/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{1,5})$";

HostnameRegex =  /^(ftp|http|https):\/\/([a-z0-9]+\.)?[a-z0-9][a-z0-9-]*((\.[a-z]{2,6})|(\.[a-z]{2,6})(\.[a-z]{2,6}))$/i

этот re используется только для проверки этого типа

работать, только если http://www.kk.com http://www.kk.co.in

не работает для

http://www.kk.com/ http://www.kk.co.in.kk

http://www.kk.com/dfas http://www.kk.co.in/

0

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

  

(<\S?!) (?:? (:\Д | [1-9]\д | 1\д\д | 2 [0-4]\д | 25 [0-5])\б |.?!\б) {7} (\ S)

  
  • 0
    Я очень старался, но я не мог понять 2 вещи здесь. 1. \ b определяет границу слова. Почему мы используем \ b? какая граница? и 2. Почему это работает только для {7} Из того, что я понял, я думаю, что это должно быть {4}, но это не работает. При желании вы можете рассказать о том, почему вы используете блоки без захвата.
0

Вот регулярное выражение, которое я использовал в Ant, чтобы получить IP-адрес прокси-сервера или имя хоста из ANT_OPTS. Это было использовано для получения IP-адреса прокси-сервера, чтобы я мог выполнить тест Ant "isreachable" перед настройкой прокси-сервера для разветвленной JVM.

^.*-Dhttp\.proxyHost=(\w{1,}\.\w{1,}\.\w{1,}\.*\w{0,})\s.*$
  • 0
    Это \w прямо здесь, он не будет захватывать IP, только имя хоста в определенных ситуациях.
-1

Я подумал об этом простом шаблоне соответствия регулярному выражению для соответствия IP-адресов \ D + [.]\D + [.]\D + [.]\Д +

  • 0
    1111.1.1.1 не является действительным ip. Там нет никакого способа по-настоящему проверить формат IP, если вы не заботитесь о подсетях. Вы должны по крайней мере позаботиться о количестве появлений с чем-то вроде ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3} и, конечно же, не будет правильным способом. Если у вас есть язык для написания скрипта, вы наверняка получите доступ к его сетевым функциям. Лучший способ проверить РЕАЛЬНЫЙ ip - это сказать системе конвертировать и ip в правильный формат, а затем проверить на true / false. В случае Python я использую socket.inet_aton(ip) . В случае PHP вам нужен inet_aton($ip) .
  • 0
    Пользователи Python могут посмотреть здесь: gist.github.com/erm3nda/f25439bba66931d3ca9699b2816e796c
-2

на php: filter_var(gethostbyname($dns), FILTER_VALIDATE_IP) == true ? 'ip' : 'not ip'

  • 2
    Хотя этот код может ответить на вопрос, в общем случае объяснение рядом с кодом делает ответ гораздо более полезным. Пожалуйста, отредактируйте свой ответ и предоставьте некоторый контекст и объяснение.
  • 0
    И, если я не ошибаюсь, FILTER_VALIDATE_IP - это значение только для PHP.
-2

как насчет этого?

([0-9]{1,3}\.){3}[0-9]{1,3}
  • 4
    с этим 777.777.777.777 действует ...
  • 0
    Как и 9999999999.0.0.9999999999 :) Но для большинства программистов этого краткого подхода будет достаточно.
Показать ещё 1 комментарий
-2

Проверка имен хостов, таких как... mywebsite.co.in, thangaraj.name, 18thangaraj.in, thangaraj106.in и т.д.,

[a-z\d+].*?\\.\w{2,4}$
  • 3
    -1. ОП попросил что-то «хорошо протестированное, чтобы точно соответствовать последним спецификациям RFC», но это не соответствует, например, * .museum, тогда как оно будет соответствовать * .foo. Вот список действительных TLD.
  • 0
    Я не уверен, что это хорошая идея - ставить плюс внутри класса символов (квадратные скобки), кроме того, есть TLD с 5 буквами (например, .expert ).
Показать ещё 1 комментарий
-3

Проверьте ipv4-решение здесь. Кажется, в ipv6 нет необходимости в настоящее время.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню