Ekspresi reguler untuk mencocokkan nama host DNS atau Alamat IP?


369

Adakah yang memiliki ekspresi reguler yang berguna yang cocok dengan nama host DNS atau alamat IP yang sah?

Sangat mudah untuk menulis yang bekerja 95% dari waktu, tetapi saya berharap untuk mendapatkan sesuatu yang diuji dengan baik agar sama persis dengan spesifikasi RFC terbaru untuk nama host DNS.

Jawaban:


535

Anda dapat menggunakan ekspresi reguler berikut secara terpisah atau dengan menggabungkannya dalam gabungan ATAU ekspresi.

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 cocok dengan alamat IP yang valid dan ValidHostnameRegex nama host yang valid. Bergantung pada bahasa yang Anda gunakan \ bisa harus lolos dengan \.


ValidHostnameRegex valid sesuai RFC 1123 . Awalnya, RFC 952 menentukan bahwa segmen nama host tidak dapat dimulai dengan angka.

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

Spesifikasi asli dari nama host di RFC 952 , mengamanatkan bahwa label tidak dapat dimulai dengan digit atau dengan tanda hubung, dan tidak boleh diakhiri dengan tanda hubung. Namun, spesifikasi berikutnya ( RFC 1123 ) mengizinkan label nama host untuk memulai dengan angka.

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])$";

3
Di sini: stackoverflow.com/questions/4645126/… - Saya menjelaskan bahwa nama yang dimulai dengan digit juga dianggap valid. Juga, hanya satu titik adalah masalah yang dipertanyakan. Akan lebih baik memiliki lebih banyak umpan balik tentang itu.
BreakPhreak

16
Anda mungkin ingin menambahkan IPv6. OP tidak menentukan jenis alamat apa. (Omong-omong, dapat ditemukan di sini )
new123456

32
Sebelum orang secara buta menggunakan ini dalam kode mereka, perhatikan bahwa itu tidak sepenuhnya akurat. Itu mengabaikan RFC2181: "DNS itu sendiri hanya menempatkan satu pembatasan pada label tertentu yang dapat digunakan untuk mengidentifikasi catatan sumber daya. Bahwa satu pembatasan berkaitan dengan panjang label dan nama lengkap. Panjang label mana pun terbatas pada antara 1 dan 63 oktet. Nama domain lengkap dibatasi hingga 255 oktet (termasuk pemisah). "
rubel

7
@UserControl: Nama host bukan latin (Punycoded) harus dikonversi ke bentuk ASCII terlebih dahulu ( éxämplè.com= xn--xmpl-loa1ab.com) dan kemudian divalidasi.
Alix Axel

6
Ekspresi nama host Anda cocok dengan beberapa nilai yang tidak valid: Saya mencoba 123.456.789.0dan mengatakan itu adalah nama host yang valid.
lbarreira

62

Regex hostname smink tidak memperhatikan batasan pada panjang label individual dalam nama host. Setiap label dalam nama host yang valid mungkin tidak lebih dari 63 oktet.

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])) * $ "

Perhatikan bahwa garis miring terbalik pada akhir baris pertama (atas) adalah sintaksis shell Unix untuk memisahkan garis panjang. Itu bukan bagian dari ekspresi reguler itu sendiri.

Ini hanya ekspresi reguler saja dalam satu baris:

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

Anda juga harus memeriksa secara terpisah bahwa panjang total nama host tidak boleh melebihi 255 karakter . Untuk informasi lebih lanjut, silakan berkonsultasi dengan RFC-952 dan RFC-1123.


6
Pola host yang luar biasa. Ini mungkin tergantung pada implementasi regex bahasa seseorang, tetapi untuk JS dapat disesuaikan sedikit menjadi lebih singkat tanpa kehilangan apa pun:/^[a-z\d]([a-z\d\-]{0,61}[a-z\d])?(\.[a-z\d]([a-z\d\-]{0,61}[a-z\d])?)*$/i
Titik koma

31

Untuk mencocokkan alamat IP yang valid gunakan regex berikut:

(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}

dari pada:

([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}

Penjelasan

Banyak mesin regex cocok dengan kemungkinan pertama dalam ORurutan. Misalnya, coba regex berikut:

10.48.0.200

Uji

Uji perbedaan antara baik vs buruk


5
Jangan lupa memulai ^ dan mengakhiri $ atau sesuatu seperti 0.0.0.999 atau 999.0.0.0 akan cocok juga. ;)
andreas

1
ya untuk memvalidasi string, mulai ^ dan akhir $ diperlukan, tetapi jika Anda mencari IP ke dalam teks, jangan gunakan itu.
Alban

'Ketidaktahuan' yang tidak disengaja yang Anda identifikasi juga berlaku untuk solusi nama host lainnya. Sebaiknya tambahkan ini ke jawaban Anda karena yang lain tidak akan cocok dengan nama host lengkap. misalnya ([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]))*versus([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])|[a-zA-Z0-9]))*
ergohack

EDIT: Di atas, gunakan +di akhir daripada *untuk melihat kegagalan.
ergohack

5

Saya sepertinya tidak dapat mengedit posting teratas, jadi saya akan menambahkan jawaban saya di sini.

Untuk hostname - jawaban mudah, pada contoh egrep di sini - http: //www.linuxinsight.com/how_to_grep_for_ip_addresses_using_the_gnu_egrep_utility.html

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

Meskipun case tidak memperhitungkan nilai-nilai seperti 0 dalam octet pertama, dan nilai lebih dari 254 (addres ip) atau 255 (netmask). Mungkin pernyataan tambahan jika akan membantu.

Adapun nama host legal dns, asalkan Anda hanya memeriksa nama host internet (dan bukan intranet), saya menulis snipped berikut ini, campuran shell / php tetapi harus berlaku sebagai ungkapan reguler apa pun.

pertama-tama pergi ke situs web ietf, unduh dan parsing daftar nama domain level 1 legal:

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)"

Itu akan memberi Anda sepotong kode ulang bagus yang memeriksa legalitas nama domain top, seperti .com .org atau .ca

Kemudian tambahkan bagian pertama dari ekspresi sesuai dengan pedoman yang ditemukan di sini - http: //www.domainit.com/support/faq.mhtml?category=Domain_FAQ&question=9 (kombinasi alfanumerik dan simbol '-' apa pun, tanda hubung tidak boleh dalam awal atau akhir oktet.

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

Kemudian kumpulkan semuanya (contoh 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
    }

Anda mungkin juga ingin menambahkan pernyataan if untuk memeriksa string yang Anda periksa lebih pendek dari 256 karakter - http://www.ops.ietf.org/lists/namedroppers/namedroppers.2003/msg00964.html


1
-1 karena ini cocok dengan alamat IP palsu seperti "999.999.999.999".
bdesham

1
"Meskipun case tidak memperhitungkan nilai-nilai seperti 0 dalam octet pertama, dan nilai lebih dari 254 (addres ip) atau 255 (netmask)."
Alex Volkov

Saya melihat bahwa Anda memenuhi syarat jawaban Anda, ya. Saya tidak memilih karena bagian dari jawaban Anda masih tidak berguna.
bdesham

3

Perlu dicatat bahwa ada perpustakaan untuk sebagian besar bahasa yang melakukan ini untuk Anda, sering dibangun ke dalam perpustakaan standar. Dan pustaka-pustaka itu cenderung diperbarui lebih sering daripada kode yang Anda salin dari jawaban Stack Overflow empat tahun lalu dan lupa. Dan tentu saja mereka juga umumnya akan mengurai alamat menjadi beberapa bentuk yang dapat digunakan, daripada hanya memberi Anda kecocokan dengan sekelompok kelompok.

Misalnya, mendeteksi dan mem-parsing IPv4 di (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;
}

Jelas, fungsi-fungsi seperti itu tidak akan berfungsi jika Anda mencoba, misalnya, menemukan semua alamat yang valid dalam pesan obrolan — tetapi bahkan di sana, mungkin lebih mudah menggunakan regex sederhana tetapi terlalu bersemangat untuk menemukan kecocokan potensial, dan kemudian menggunakan perpustakaan untuk menguraikannya.

Misalnya, dalam 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

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("."))

Bisakah Anda menjelaskan regex ini? Tepatnya, apa artinya (?! -), (? <! -)?
Lempar

1
@Scit, mereka memastikan itu tidak memulai atau mengakhiri dengan karakter "-" jika mesin regex Anda mengizinkan penggunaannya. Misalnya, dari Python atau dari Perl .
YPelajari

1

Saya pikir ini adalah regex validasi Ip terbaik. tolong periksa sekali !!!

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

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

Ini berfungsi untuk alamat IP yang valid:

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
/^(?:[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])?$/

0

Ini adalah regex yang saya gunakan di Ant untuk mendapatkan IP host proxy atau nama host dari ANT_OPTS. Ini digunakan untuk mendapatkan IP proxy sehingga saya bisa menjalankan tes "isreachable" semut sebelum mengkonfigurasi proxy untuk JVM bercabang dua.

^.*-Dhttp\.proxyHost=(\w{1,}\.\w{1,}\.\w{1,}\.*\w{0,})\s.*$

Itu di \wsana, tidak akan menangkap IP, hanya nama host pada situasi tertentu.
Yaron

0

Saya menemukan ini berfungsi dengan baik untuk alamat IP. Ini memvalidasi seperti jawaban teratas tetapi juga memastikan ip terisolasi sehingga tidak ada teks atau lebih banyak angka / desimal setelah atau sebelum ip.

(? <! \ S) (?: (?: \ D | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5]) \ b |. \ b) {7} (?! \ S)


Saya mencoba banyak tetapi saya tidak bisa mengerti 2 hal di sini. 1. \ b menentukan batas kata Mengapa kita menggunakan \ b? yang merupakan batas? dan 2. Mengapa hanya berfungsi untuk {7} Dari apa yang saya mengerti, saya pikir seharusnya {4} tetapi, itu tidak berfungsi. Secara opsional, Anda dapat mengetahui mengapa Anda menggunakan blok yang tidak menangkap.
Srichakradhar


0

coba ini:

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

itu berfungsi dalam kasus saya.


0

Mengenai alamat IP, tampaknya ada beberapa perdebatan tentang apakah akan memasukkan angka nol di depan. Itu dulunya praktik umum dan diterima secara umum, jadi saya berpendapat bahwa mereka harus ditandai sebagai valid terlepas dari preferensi saat ini. Ada juga beberapa ambiguitas tentang apakah teks sebelum dan sesudah string harus divalidasi dan, sekali lagi, saya pikir seharusnya. 1.2.3.4 adalah IP yang valid tetapi 1.2.3.4.5 tidak dan bagian 1.2.3.4 atau 2.3.4.5 tidak menghasilkan pertandingan. Beberapa masalah dapat ditangani dengan ungkapan ini:

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:]]|$)' 

Bagian yang disayangkan di sini adalah kenyataan bahwa bagian regex yang memvalidasi oktet diulangi seperti yang terjadi pada banyak solusi yang ditawarkan. Meskipun ini lebih baik daripada untuk contoh pola, pengulangan dapat dihilangkan seluruhnya jika subrutin didukung dalam regex yang digunakan. Contoh berikutnya memungkinkan fungsi-fungsi dengan -Psaklar grepdan juga mengambil keuntungan dari fungsi lookahead dan lookhhind. (Nama fungsi yang saya pilih adalah 'o' untuk oktet. Saya bisa menggunakan 'oktet' sebagai nama tetapi ingin menjadi singkat.)

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

Penanganan titik sebenarnya dapat membuat negatif palsu jika alamat IP dalam file dengan teks dalam bentuk kalimat karena periode dapat mengikuti tanpa menjadi bagian dari notasi bertitik. Varian di atas akan memperbaikinya:

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
>>> 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

Kerangka kerja Jaringan baru telah menyediakan inisialisasi untuk struct IPv4Address dan struct IPv6Address yang menangani bagian alamat IP dengan sangat mudah. Melakukan ini di IPv6 dengan regex sangat sulit dengan semua aturan pemendekan.

Sayangnya saya tidak punya jawaban elegan untuk nama host.

Perhatikan bahwa Kerangka kerja jaringan terbaru, sehingga dapat memaksa Anda untuk mengkompilasi untuk versi OS terbaru.

import Network
let tests = ["192.168.4.4","fkjhwojfw","192.168.4.4.4","2620:3","2620::33"]

for test in tests {
    if let _ = IPv4Address(test) {
        debugPrint("\(test) is valid ipv4 address")
    } else if let _ = IPv6Address(test) {
        debugPrint("\(test) is valid ipv6 address")
    } else {
        debugPrint("\(test) is not a valid IP address")
    }
}

output:
"192.168.4.4 is valid ipv4 address"
"fkjhwojfw is not a valid IP address"
"192.168.4.4.4 is not a valid IP address"
"2620:3 is not a valid IP address"
"2620::33 is valid ipv6 address"

-1

bagaimana dengan ini?

([0-9]{1,3}\.){3}[0-9]{1,3}

Dan demikian juga 9999999999.0.0.9999999999 :) Tetapi bagi kebanyakan programmer, pendekatan singkat ini sudah cukup.
andreas

3
-1 karena ini cocok dengan alamat IP yang tidak masuk akal (seperti catatan @Shebuka).
bdesham

-1

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


2
Meskipun kode ini dapat menjawab pertanyaan, umumnya penjelasan di samping kode membuat jawaban jauh lebih berguna. Harap edit jawaban Anda dan berikan beberapa konteks dan penjelasan.
user4642212

Dan, kecuali saya salah, FILTER_VALIDATE_IP adalah nilai hanya PHP.
DonGar

-2

Memeriksa nama host seperti ... mywebsite.co.in, thangaraj.name, 18thangaraj.in, thangaraj106.in dll,

[a-z\d+].*?\\.\w{2,4}$

3
-1. OP meminta sesuatu “teruji dengan baik agar sama persis dengan spesifikasi RFC terbaru”, tetapi ini tidak cocok misalnya * .museum, sementara itu akan cocok dengan * .foo. Berikut daftar TLD yang valid.
bdesham

Saya tidak yakin itu ide yang baik untuk menempatkan nilai tambah di dalam kelas karakter (tanda kurung siku), lebih jauh lagi, ada TLD dengan 5 huruf ( .exp misalnya).
Yaron

Cara terbaik untuk mencapai dengan RFC adalah dengan menggunakan fungsi sistem / bahasa. inet_atoncukup baik
m3nda

-2

Saya memikirkan pola pencocokan regex sederhana ini untuk pencocokan alamat IP \ d + [.] \ D + [.] \ D + [.] \ D +


1111.1.1.1 bukan ip yang valid. Tidak ada cara untuk benar-benar menguji format ip jika Anda tidak peduli tentang subnet. Anda setidaknya harus berhati-hati tentang jumlah penampilan dengan sesuatu seperti ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}dan tentu saja itu tidak akan menjadi cara yang benar. Jika Anda memiliki bahasa untuk menulis skrip, pasti Anda akan memiliki akses ke fungsi jaringan itu. Cara terbaik untuk memeriksa ip REAL itu untuk memberitahu sistem untuk mengkonversi dan ip ke format yang benar kemudian periksa benar / salah. Dalam kasus Python saya gunakan socket.inet_aton(ip). PHP yang Anda butuhkan inet_aton($ip).
m3nda

Pengguna Python dapat melihatnya di sini: gist.github.com/erm3nda/f25439bba66931d3ca9699b2816e796c
m3nda
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.