นิพจน์ทั่วไปที่ดีที่สุดในการตรวจสอบว่าสตริงเป็น URL ที่ถูกต้องคืออะไร


797

ฉันจะตรวจสอบว่าสตริงที่กำหนดเป็นที่อยู่ URL ที่ถูกต้องได้อย่างไร?

ความรู้ของฉันเกี่ยวกับนิพจน์ทั่วไปนั้นเป็นพื้นฐานและไม่อนุญาตให้ฉันเลือกจากนิพจน์ทั่วไปนับร้อยที่ฉันได้เห็นบนเว็บแล้ว


31
URL ใด ๆ หรือเพียงแค่ HTTP? เช่น mailto: me@example.com นับเป็น URL หรือไม่ ลิงค์แชท AIM?
Mecki

1
หาก URL ไม่มี "http (ฯลฯ )" นำหน้าคุณจะแยกความแตกต่างได้อย่างไรจากสตริงอื่นใดที่เกิดขึ้นเพื่อให้มีจุดอยู่ภายใน พูดบางอย่างเช่น "MyClass.MyProperty.MyMethod" หรือ "บางครั้งฉันคิดถึงสเปซบาร์นี่เป็นปัญหาหรือไม่"
Tomalak

1
ฉันได้ใส่คำนำหน้า 'http: / / www แล้ว' หน้ากล่องข้อความ ดังนั้นผู้ใช้ไม่จำเป็นต้องป้อน 'http: / / www' และควรเกี่ยวข้องกับการป้อนชื่อ uri ที่ต้องการ
ป้อน

1
คุณใช้ภาษาโปรแกรมอะไร คุณอาจไม่ต้องการบูรณาการล้อ
เงินที่จ่าย

9
Microsoft มีหน้า Regex ที่มีนิพจน์สำหรับ URL เป็นการเริ่มต้นที่ดีอย่างแน่นอน: msdn.microsoft.com/en-us/library/ff650303.aspx NB หน้าข้างต้นถูกยกเลิก แต่นิพจน์ในตารางยังคงใช้งานได้สำหรับการอ้างอิงเป็นหลัก นิพจน์ URL ที่แนะนำ (และใช้งานได้ดีกับฉัน) คือ: "^ (ht | f) tp (s?) \: \ / \ / [0-9a-zA-Z] ([-. \ w] * [ 0-9a-za-Z]) * (:( 0-9) *) * (\ /) ([a-zA-Z0-9 \? -. \ \ \, \ '\ / \\\ + & amp;% \ $ # _] *)? $ "
CMH

คำตอบ:


408

ฉันเขียน URL ของฉัน (จริง ๆ แล้ว IRI เป็นสากล) รูปแบบเพื่อให้สอดคล้องกับ RFC 3987 ( http://www.faqs.org/rfcs/rfc3987.html ) สิ่งเหล่านี้อยู่ในรูปแบบ PCRE

สำหรับไอริสสัมบูรณ์ (สากล):

/^[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i

ในการอนุญาตให้ IRIs ที่สัมพันธ์กัน:

/^(?:[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\/\?])*)?|(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=@])+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\/\?])*)?)$/i

วิธีรวบรวม (ใน PHP):

<?php

/* Regex convenience functions (character class, non-capturing group) */
function cc($str, $suffix = '', $negate = false) {
    return '[' . ($negate ? '^' : '') . $str . ']' . $suffix;
}
function ncg($str, $suffix = '') {
    return '(?:' . $str . ')' . $suffix;
}

/* Preserved from RFC3986 */

$ALPHA = 'a-z';
$DIGIT = '0-9';
$HEXDIG = $DIGIT . 'a-f';

$sub_delims = '!\\$&\'\\(\\)\\*\\+,;=';
$gen_delims = ':\\/\\?\\#\\[\\]@';
$reserved = $gen_delims . $sub_delims;
$unreserved = '-' . $ALPHA . $DIGIT . '\\._~';

$pct_encoded = '%' . cc($HEXDIG) . cc($HEXDIG);

$dec_octet = ncg(implode('|', array(
    cc($DIGIT),
    cc('1-9') . cc($DIGIT),
    '1' . cc($DIGIT) . cc($DIGIT),
    '2' . cc('0-4') . cc($DIGIT),
    '25' . cc('0-5')
)));

$IPv4address = $dec_octet . ncg('\\.' . $dec_octet, '{3}');

$h16 = cc($HEXDIG, '{1,4}');
$ls32 = ncg($h16 . ':' . $h16 . '|' . $IPv4address);

$IPv6address = ncg(implode('|', array(
    ncg($h16 . ':', '{6}') . $ls32,
    '::' . ncg($h16 . ':', '{5}') . $ls32,
    ncg($h16, '?') . '::' . ncg($h16 . ':', '{4}') . $ls32,
    ncg($h16 . ':' . $h16, '?') . '::' . ncg($h16 . ':', '{3}') . $ls32,
    ncg(ncg($h16 . ':', '{0,2}') . $h16, '?') . '::' . ncg($h16 . ':', '{2}') . $ls32,
    ncg(ncg($h16 . ':', '{0,3}') . $h16, '?') . '::' . $h16 . ':' . $ls32,
    ncg(ncg($h16 . ':', '{0,4}') . $h16, '?') . '::' . $ls32,
    ncg(ncg($h16 . ':', '{0,5}') . $h16, '?') . '::' . $h16,
    ncg(ncg($h16 . ':', '{0,6}') . $h16, '?') . '::',
)));

$IPvFuture = 'v' . cc($HEXDIG, '+') . cc($unreserved . $sub_delims . ':', '+');

$IP_literal = '\\[' . ncg(implode('|', array($IPv6address, $IPvFuture))) . '\\]';

$port = cc($DIGIT, '*');

$scheme = cc($ALPHA) . ncg(cc('-' . $ALPHA . $DIGIT . '\\+\\.'), '*');

/* New or changed in RFC3987 */

$iprivate = '\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}';

$ucschar = '\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}' .
    '\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}' .
    '\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}' .
    '\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}' .
    '\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}' .
    '\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}';

$iunreserved = '-' . $ALPHA . $DIGIT . '\\._~' . $ucschar;

$ipchar = ncg($pct_encoded . '|' . cc($iunreserved . $sub_delims . ':@'));

$ifragment = ncg($ipchar . '|' . cc('\\/\\?'), '*');

$iquery = ncg($ipchar . '|' . cc($iprivate . '\\/\\?'), '*');

$isegment_nz_nc = ncg($pct_encoded . '|' . cc($iunreserved . $sub_delims . '@'), '+');
$isegment_nz = ncg($ipchar, '+');
$isegment = ncg($ipchar, '*');

$ipath_empty = '(?!' . $ipchar . ')';
$ipath_rootless = ncg($isegment_nz) . ncg('\\/' . $isegment, '*');
$ipath_noscheme = ncg($isegment_nz_nc) . ncg('\\/' . $isegment, '*');
$ipath_absolute = '\\/' . ncg($ipath_rootless, '?'); // Spec says isegment-nz *( "/" isegment )
$ipath_abempty = ncg('\\/' . $isegment, '*');

$ipath = ncg(implode('|', array(
    $ipath_abempty,
    $ipath_absolute,
    $ipath_noscheme,
    $ipath_rootless,
    $ipath_empty
))) . ')';

$ireg_name = ncg($pct_encoded . '|' . cc($iunreserved . $sub_delims . '@'), '*');

$ihost = ncg(implode('|', array($IP_literal, $IPv4address, $ireg_name)));
$iuserinfo = ncg($pct_encoded . '|' . cc($iunreserved . $sub_delims . ':'), '*');
$iauthority = ncg($iuserinfo . '@', '?') . $ihost . ncg(':' . $port, '?');

$irelative_part = ncg(implode('|', array(
    '\\/\\/' . $iauthority . $ipath_abempty . '',
    '' . $ipath_absolute . '',
    '' . $ipath_noscheme . '',
    '' . $ipath_empty . ''
)));

$irelative_ref = $irelative_part . ncg('\\?' . $iquery, '?') . ncg('\\#' . $ifragment, '?');

$ihier_part = ncg(implode('|', array(
    '\\/\\/' . $iauthority . $ipath_abempty . '',
    '' . $ipath_absolute . '',
    '' . $ipath_rootless . '',
    '' . $ipath_empty . ''
)));

$absolute_IRI = $scheme . ':' . $ihier_part . ncg('\\?' . $iquery, '?');

$IRI = $scheme . ':' . $ihier_part . ncg('\\?' . $iquery, '?') . ncg('\\#' . $ifragment, '?');

$IRI_reference = ncg($IRI . '|' . $irelative_ref);

แก้ไข 7 มีนาคม 2011: เนื่องจากวิธีที่ PHP จัดการแบ็กสแลชในสตริงที่ยกมาสิ่งเหล่านี้จึงใช้ไม่ได้โดยค่าเริ่มต้น คุณจะต้องหลบหลีกแบ็กสแลชสองครั้งยกเว้นว่าแบ็กสแลชนั้นมีความหมายพิเศษใน regex คุณสามารถทำได้เช่นนี้:

$escape_backslash = '/(?<!\\)\\(?![\[\]\\\^\$\.\|\*\+\(\)QEnrtaefvdwsDWSbAZzB1-9GX]|x\{[0-9a-f]{1,4}\}|\c[A-Z]|)/';
$absolute_IRI = preg_replace($escape_backslash, '\\\\', $absolute_IRI);
$IRI = preg_replace($escape_backslash, '\\\\', $IRI);
$IRI_reference = preg_replace($escape_backslash, '\\\\', $IRI_reference);

74
หากคุณคิดว่าไม่ดีคุณควรเห็นอีเมลดังกล่าว: ex-parrot.com/~pdw/Mail-RFC822-Address.html
Peter Di Cecco

12
@Gumbo มันได้รับอนุญาตในข้อมูลจำเพาะและใช้ในการปรับใช้ URI สำหรับแอปพลิเคชัน HTTP มันเป็นท้อแท้ (ด้วยเหตุผลที่ชัดเจน) แต่ก็ใช้ได้อย่างสมบูรณ์และควรได้รับการคาดหวัง เบราว์เซอร์ส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) บางครั้งแปลการรับรองความถูกต้อง HTTP เป็น URL สำหรับการเข้าถึงครั้งต่อไป
เปลือกตา

12
@Devin ในฟังก์ชั่นในภาษาใด? ฉันรวบรวมใน PHP แต่มันสามารถใช้ในภาษาอื่น ๆ ฉันควรเขียนฟังก์ชั่นในทุกภาษาเหล่านั้นหรือไม่? มันอาจจะง่ายสำหรับคุณที่จะทำเช่นเดียวกันในภาษาที่คุณเลือก
เปลือกตา

6
@joshcomley แทนที่ \ x {ABCD} เป็น \ uABCD ถ้าคุณเขียนใน JS
bruha

4
ใช่http://comเป็น URL ที่ถูกต้อง http://localhostเหตุใดจึงไม่มีคำอื่น ๆ คุณถูกต้องว่าuจำเป็นต้องมีการดัดแปลงใน PHP ฉันต้องการชัดเจนว่าในขณะที่ฉันสร้างสิ่งเหล่านี้ด้วย PHP พวกเขาไม่ได้ตั้งใจเป็นเฉพาะ PHP
เปลือกตา

153

ฉันเพิ่งเขียนโพสต์บล็อกเพื่อหาทางออกที่ดีสำหรับการจดจำ URL ในรูปแบบที่ใช้บ่อยที่สุดเช่น:

  • www.google.com
  • http://www.google.com
  • mailto:somebody@google.com
  • somebody@google.com
  • www.url-with-querystring.com/?url=has-querystring

นิพจน์ทั่วไปที่ใช้คือ:

/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/

17
อันนั้นก็ใช้งานได้ แต่ก็ขาดการรองรับหมายเลขพอร์ต (มีประโยชน์ในการดีบัก) แก้ไขแล้วจะ/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/
Jaime Cham

2
Regex นี้ไม่จัดการลิงก์ที่มีวงเล็บในตัวอย่างเช่น msdn.microsoft.com/en-us/library/ms563775(v=office.14).aspx
RobH

4
ไม่ควรให้จุดหลุดหลังจาก www?
แอนโธนี

13
มีคู่ที่ตรงกันอีก: width:210px;และmargin:3px
Cas Bloem

1
ไม่ตรงกับ "example.com" ... หรือไม่
กุสตาฟ

80

แพลตฟอร์มอะไร หากใช้. NET ให้ใช้System.Uri.TryCreateไม่ใช่ regex

ตัวอย่างเช่น:

static bool IsValidUrl(string urlString)
{
    Uri uri;
    return Uri.TryCreate(urlString, UriKind.Absolute, out uri)
        && (uri.Scheme == Uri.UriSchemeHttp
         || uri.Scheme == Uri.UriSchemeHttps
         || uri.Scheme == Uri.UriSchemeFtp
         || uri.Scheme == Uri.UriSchemeMailto
            /*...*/);
}

// In test fixture...

[Test]
void IsValidUrl_Test()
{
    Assert.True(IsValidUrl("http://www.example.com"));
    Assert.False(IsValidUrl("javascript:alert('xss')"));
    Assert.False(IsValidUrl(""));
    Assert.False(IsValidUrl(null));
}

(ขอบคุณ@Yoshiสำหรับคำแนะนำเกี่ยวกับjavascript:)


6
Uri.TryCreate () ผลตอบแทนจริงถ้ามันเป็นสิ่งที่ถูกต้อง
Duncan Smart

112
คำเตือนขนาดใหญ่ให้กับทุกคนที่ใช้เทคนิคนี้: System.Uri javascript: alert('blah')อย่างถูกต้องยอมรับ ที่คุณต้องทำการตรวจสอบเพิ่มเติมเกี่ยวกับUri.Schemeเพื่อยืนยันโปรโตคอล HTTP / HTTPS / FTP จะถูกใช้อย่างอื่นถ้าเช่น URL ที่ถูกแทรกลงในเพจ ASP.NET ของ HTML เป็นลิงก์ให้ผู้ใช้ของคุณเสี่ยงต่อการโจมตี XSS
Yoshi

23
โดยเฉพาะ Uri.TryCreate จะส่งกลับค่าจริงสำหรับสตริงว่างเช่นกัน ดูเหมือนว่า TryCreate จะไม่มีประสิทธิภาพมากนัก ...
Steven Evers

1
จะทำอย่างไรถ้าฉันต้องการให้ regex ทำเซิร์ฟเวอร์ / ฝั่งไคลเอ็นต์ในแอพ ASP.NET MVC สิ่งนี้จะช่วยลูกค้าได้อย่างไร
Andrei Rînea

4
สำหรับ. Net ให้ใช้Uri.IsWellFormedUriString()
mheyman

57

นี่คือสิ่งที่RegexBuddyใช้

(\b(https?|ftp|file)://)?[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]

มันตรงกับด้านล่าง (ภายใน** **เครื่องหมาย):

**http://www.regexbuddy.com**  
**http://www.regexbuddy.com/**  
**http://www.regexbuddy.com/index.html**  
**http://www.regexbuddy.com/index.html?source=library**  

คุณสามารถดาวน์โหลด RegexBuddy ที่http://www.regexbuddy.com/download.html


29
แล้วโกเฟอร์ล่ะ? แย่โกเฟอร์ลืม
toohool

3
regex ของคุณไม่ตรงกับ URL ที่ฉันสามารถหาได้รวมถึงที่คุณรวมไว้ด้วย ฉันวาง regex ของคุณลงในrubular.comและมีข้อความระบุว่า "ต้องใช้เครื่องหมายทับซ้ายเพื่อหนี" มีการพิมพ์ผิดหรือคุณสามารถอธิบายให้ชัดเจนขึ้นโดยการทำให้มันทำงานที่ rubular.com หรือไม่?
PandaWood

3
@PandaWood นั่นเป็นเพราะคุณต้องฟอร์แมตสำหรับ Ruby ตัวละครในการหลบหนีของรูบี้คืออะไร?
เก่ง

18
ในฐานะที่เป็น JavaScript RegExp ตัวอักษร:/\b(https?|ftp|file):\/\/[\-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_|]/
jpillora

1
@toohool อย่างน้อยโกเฟอร์กินเวลานานกว่าอาร์ชี : - \ (ผู้คนยังจับนิ้วอยู่หรือเปล่า? 🤔)
Synetech

44

เกี่ยวกับหนังตาคำตอบของที่อ่านว่า "นี่เป็นไปตามการอ่านข้อกำหนด URI ของฉัน": ขอบคุณเปลือกตาของคุณเป็นคำตอบที่สมบูรณ์แบบที่ฉันต้องการ ผลงานยอดเยี่ยม :)

ฉันต้องแก้ไขสองครั้ง คนแรกที่ได้รับ regexp เพื่อจับคู่ URL ที่อยู่ IP อย่างถูกต้องใน PHP (v5.2.10) กับฟังก์ชั่น preg_match ()

ฉันต้องเพิ่มวงเล็บอีกหนึ่งชุดในบรรทัดด้านบน "ที่อยู่ IP" รอบ ๆ ท่อ:

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

ไม่แน่ใจว่าทำไม

ฉันได้ลดความยาวขั้นต่ำของโดเมนระดับบนสุดจาก 3 เป็น 2 ตัวอักษรเพื่อรองรับ. co.uk และที่คล้ายกัน

รหัสสุดท้าย:

/^(https?|ftp):\/\/(?#                                      protocol
)(([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+(?#         username
)(:([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+)?(?#      password
)@)?(?#                                                     auth requires @
)((([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*(?#             domain segments AND
)[a-z][a-z0-9-]*[a-z0-9](?#                                 top level domain  OR
)|((\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])\.){3}(?#
    )(\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])(?#             IP address
))(:\d+)?(?#                                                port
))(((\/+([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)*(?# path
)(\?([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)(?#      query string
)?)?)?(?#                                                   path and query string optional
)(#([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)?(?#      fragment
)$/i

เวอร์ชันที่ปรับเปลี่ยนนี้ไม่ได้ตรวจสอบกับข้อกำหนดของ URI ดังนั้นฉันจึงไม่สามารถรับรองได้ว่ามันเป็นไปตามมาตรฐาน แต่ก็มีการเปลี่ยนแปลงเพื่อจัดการ URL ในสภาพแวดล้อมเครือข่ายท้องถิ่นและ TLD สองหลักรวมถึง URL ประเภทอื่น ๆ และทำงานได้ดีขึ้นใน PHP ฉันใช้

ในฐานะที่เป็นรหัสPHP :

define('URL_FORMAT', 
'/^(https?):\/\/'.                                         // protocol
'(([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+'.         // username
'(:([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+)?'.      // password
'@)?(?#'.                                                  // auth requires @
')((([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*'.                      // domain segments AND
'[a-z][a-z0-9-]*[a-z0-9]'.                                 // top level domain  OR
'|((\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])\.){3}'.
'(\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])'.                 // IP address
')(:\d+)?'.                                                // port
')(((\/+([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)*'. // path
'(\?([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)'.      // query string
'?)?)?'.                                                   // path and query string optional
'(#([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)?'.      // fragment
'$/i');

นี่คือโปรแกรมทดสอบใน PHP ซึ่งตรวจสอบความถูกต้องของ URL โดยใช้ regex:

<?php

define('URL_FORMAT',
'/^(https?):\/\/'.                                         // protocol
'(([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+'.         // username
'(:([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+)?'.      // password
'@)?(?#'.                                                  // auth requires @
')((([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*'.                      // domain segments AND
'[a-z][a-z0-9-]*[a-z0-9]'.                                 // top level domain  OR
'|((\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])\.){3}'.
'(\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])'.                 // IP address
')(:\d+)?'.                                                // port
')(((\/+([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)*'. // path
'(\?([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)'.      // query string
'?)?)?'.                                                   // path and query string optional
'(#([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)?'.      // fragment
'$/i');

/**
 * Verify the syntax of the given URL. 
 * 
 * @access public
 * @param $url The URL to verify.
 * @return boolean
 */
function is_valid_url($url) {
  if (str_starts_with(strtolower($url), 'http://localhost')) {
    return true;
  }
  return preg_match(URL_FORMAT, $url);
}


/**
 * String starts with something
 * 
 * This function will return true only if input string starts with
 * niddle
 * 
 * @param string $string Input string
 * @param string $niddle Needle string
 * @return boolean
 */
function str_starts_with($string, $niddle) {
      return substr($string, 0, strlen($niddle)) == $niddle;
}


/**
 * Test a URL for validity and count results.
 * @param url url
 * @param expected expected result (true or false)
 */

$numtests = 0;
$passed = 0;

function test_url($url, $expected) {
  global $numtests, $passed;
  $numtests++;
  $valid = is_valid_url($url);
  echo "URL Valid?: " . ($valid?"yes":"no") . " for URL: $url. Expected: ".($expected?"yes":"no").". ";
  if($valid == $expected) {
    echo "PASS\n"; $passed++;
  } else {
    echo "FAIL\n";
  }
}

echo "URL Tests:\n\n";

test_url("http://localserver/projects/public/assets/javascript/widgets/UserBoxMenu/widget.css", true);
test_url("http://www.google.com", true);
test_url("http://www.google.co.uk/projects/my%20folder/test.php", true);
test_url("https://myserver.localdomain", true);
test_url("http://192.168.1.120/projects/index.php", true);
test_url("http://192.168.1.1/projects/index.php", true);
test_url("http://projectpier-server.localdomain/projects/public/assets/javascript/widgets/UserBoxMenu/widget.css", true);
test_url("https://2.4.168.19/project-pier?c=test&a=b", true);
test_url("https://localhost/a/b/c/test.php?c=controller&arg1=20&arg2=20", true);
test_url("http://user:password@localhost/a/b/c/test.php?c=controller&arg1=20&arg2=20", true);

echo "\n$passed out of $numtests tests passed.\n\n";

?>

ขอขอบคุณอีกครั้งที่หนังตาสำหรับ regex!


1
คำตอบของเปลือกตาไม่ได้ผลสำหรับฉัน แต่อันนี้ทำ ขอบคุณ!
Josh

อันนี้ใช้งานได้ใน JavaScript แต่ฉันไม่สามารถรับหนึ่งเปลือกตาที่ให้ไว้ใน JS แม้หลังจากแทนที่ \ x ด้วย \ u เพื่อหลบหนีอักขระ unicode
jimmym715

5
ความคิดเห็นของSho Kuwamoto : "ฉันลงเอยด้วยการใช้ regex โดยผู้ใช้ 244966 ซึ่งสำหรับฉันคือการผสมผสานที่สมบูรณ์แบบของการอ่าน แต่อย่างละเอียดอย่างไรก็ตามมีประเด็นสำคัญ MAJOR ใน regex .... regex ของเขา / เธอล้มเหลวในโดเมนที่ มีชิ้นส่วนอักขระหนึ่งตัวเช่นt.coการแก้ไขคือการแทนที่บรรทัดนี้')((([a-z0-9][a-z0-9-]*[a-z0-9]\.)*'.ด้วย')((([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*'." ฉันได้ทำการแก้ไขที่เกี่ยวข้องตามความคิดเห็นนี้
Peter O.

ทำงานได้อย่างสวยงาม! อย่างไรก็ตามฉันเพิ่งอนุญาตให้ตัวเองเพิ่มการรองรับพา ธ ด้วยอักขระเครื่องหมายตัวหนอน (~) โดยเพิ่มลงในบรรทัดที่สอดคล้องกับเส้นทาง
Leo สนับสนุน Monica Cellio

/^(https?|ftp):(โปรโตคอล) ทำไมคุณไม่อนุญาตโปรโตคอลเช่นข้อมูล, ไฟล์, svn, dc ++, แม่เหล็ก, skype หรืออื่น ๆ ที่เบราว์เซอร์รองรับที่มีปลั๊กอินหรือเซิร์ฟเวอร์ที่สอดคล้องกัน
Aleksey F.

43

Mathias Bynens มีบทความที่ยอดเยี่ยมเกี่ยวกับการเปรียบเทียบการแสดงออกปกติจำนวนมากที่สุด: ค้นหาการตรวจสอบความถูกต้องของ URL ที่สมบูรณ์แบบ

โพสต์ที่ดีที่สุดนั้นยาวนิดหน่อย แต่มันตรงกับอะไรก็ได้ที่คุณสามารถโยนได้

เวอร์ชัน JavaScript

/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i

รุ่น PHP

_^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$_iuS

1
สำหรับการใช้งาน preg_match กับการใช้งาน PHP %^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu
Toby Beresford

ในหน้านั้นฉันชอบโซลูชันของ stephenhay เพราะมันเป็น 38 ตัวอักษรแทนที่จะเป็น 502!
Venryx

ยังไม่อนุญาตสำหรับที่อยู่ IP
Matt Fletcher

ให้ถูกต้อง (เครื่องหมายทับ): //www.2test.com/
stackdave

33

โพสต์การรับชิ้นส่วนของ URL (Regex)อธิบายการแยกวิเคราะห์ URL เพื่อระบุส่วนประกอบต่างๆ หากคุณต้องการตรวจสอบว่า URL มีรูปแบบที่ดีหรือไม่ก็ควรจะเพียงพอสำหรับความต้องการของคุณ

หากคุณจำเป็นต้องตรวจสอบว่ามันใช้งานได้จริงในที่สุดคุณจะต้องพยายามเข้าถึงสิ่งที่อยู่ในส่วนอื่น ๆ

โดยทั่วไปแล้วคุณอาจจะดีกว่าถ้าใช้ฟังก์ชั่นที่มอบให้คุณโดยเฟรมเวิร์กหรือไลบรารีอื่น หลายแพลตฟอร์มมีฟังก์ชั่นที่ใช้ในการแยกวิเคราะห์ URL ตัวอย่างเช่นมีโมดูลurlparseของ Python และใน. NET คุณสามารถใช้Constructor ของคลาส System.Uriเพื่อตรวจสอบ URL ได้


22

นี่อาจไม่ใช่งานสำหรับ regexes แต่สำหรับเครื่องมือที่มีอยู่ในภาษาที่คุณเลือก คุณอาจต้องการใช้รหัสที่มีอยู่ซึ่งถูกเขียนทดสอบและดีบั๊กแล้ว

ใน PHP ใช้parse_urlฟังก์ชัน

Perl: โมดูลURI

ทับทิม: โมดูลURI

.NET: คลาส 'Uri'

Regexes ไม่ใช่เวทย์มนตร์ที่คุณโบกไปมาในทุกปัญหาที่เกิดขึ้นจากการเกี่ยวข้องกับสตริง


7
ประโยคสุดท้ายของคุณทำให้ฉันนึกถึงLaw of the เครื่องดนตรี / ค้อนของ Maslow : "ถ้าคุณมีแค่ค้อนทุกอย่างก็ดูเหมือนเป็นเล็บ"
DavidRR

3
อย่างไรก็ตาม Regexes นั้นสวยงามสำหรับการแยก URL ออกจากเนื้อความธรรมดา หากคุณสงสัยทั้งปวงของสตริงคือ URL แล้วผม 100% เห็นด้วยกับคุณและพูดถึงว่าของ Java java.net.URLที่เทียบเท่า
ndm13

2
เอกสารสำหรับ parse_url ในสถานะ PHP: ฟังก์ชั่นนี้ไม่ได้มีไว้เพื่อตรวจสอบความถูกต้องของ URL ที่กำหนด แต่จะแบ่งออกเป็นส่วนที่ระบุไว้ข้างต้นเท่านั้น
Doug Amos

18

Parser อ้างอิง URI ที่ไม่ผ่านการตรวจสอบ

สำหรับวัตถุประสงค์ในการอ้างอิงนี่คือข้อมูลจำเพาะของ IETF: ( TXT | HTML ) โดยเฉพาะอย่างยิ่งภาคผนวกขแยกอ้างอิง URI กับนิพจน์ปกติแสดงให้เห็นถึงวิธีการที่จะแยกregex ที่ถูกต้อง นี่คือคำอธิบาย

สำหรับตัวอย่างของตัวแยกวิเคราะห์อ้างอิง URI ที่ไม่ผ่านการตรวจสอบซึ่งจะใช้สตริงที่กำหนดและแยกส่วนประกอบ URI

นี่คือ regex ที่พวกเขาให้:

 ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?

อย่างที่คนอื่นพูดกันคงเป็นการดีที่สุดที่จะปล่อยให้สิ่งนี้เป็น lib / framework ที่คุณใช้อยู่


15
ไร้ประโยชน์โดยสิ้นเชิง ใครสามารถแสดงสตริงที่ regex นี้ไม่ตรงกับฉัน (ทั้งคู่ "#? #? #" หรือ "<<< >>>" การจับคู่ของ URIs ประเภทใดกัน)
Alex D

3
@AlexD อย่าบ่นกับฉัน นั่นเป็นข้อกำหนดอย่างเป็นทางการสำหรับ URI นำมันไปใช้กับ IETF ถ้าคุณไม่ชอบ
แฮงค์เกย์

1
@AlexD ผมคิดว่าเหล่านั้นอาจได้รับการพิจารณาการอ้างอิงแบบสัมพัทธ์ ดู RFC 3986 ส่วน 4.2
andyg0808

3
@ และ yg0808 คุณอาจจะถูก แต่ความจริงก็ยังคงอยู่ที่ regex นี้ตรงกับสายใด ๆ ภายใต้ดวงอาทิตย์
Alex D

1
นี่ไม่ใช่คำตอบที่ดีเพราะมันไม่ผ่านการตรวจสอบตามคำถาม มันแยกวิเคราะห์ ฟังก์ชั่นที่แตกต่างกันสองอย่าง ถ้าคุณให้ถังขยะ Regex นี้มันพยายามที่จะแยกมัน หาก URL ไม่ถูกต้องการวิเคราะห์คำจะไม่ทำงาน
Evan Carroll

15

สิ่งนี้จะตรงกับ URL ทั้งหมด

  • มีหรือไม่มีhttp / https
  • มีหรือไม่มีwww

... รวมถึงโดเมนย่อยและส่วนขยายชื่อโดเมนระดับบนสุดใหม่เช่น พิพิธภัณฑ์ ,. สถานศึกษา ,. มูลนิธิ ฯลฯ ซึ่งสามารถมีได้ถึง 63 ตัวอักษร (ไม่เพียง. คอม . สุทธิ . ข้อมูลอื่น ๆ )

(([\w]+:)?//)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,63}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?

เพราะวันนี้ความยาวสูงสุดของนามสกุลโดเมนระดับบนสุดที่มีคือ 13 ตัวอักษรเช่น ระหว่างประเทศคุณสามารถเปลี่ยนหมายเลข 63 ในนิพจน์เป็น 13 เพื่อป้องกันไม่ให้บุคคลอื่นใช้ผิดวัตถุประสงค์

เป็นจาวาสคริปต์

var urlreg=/(([\w]+:)?\/\/)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,63}(:[\d]+)?(\/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?/;

$('textarea').on('input',function(){
  var url = $(this).val();
  $(this).toggleClass('invalid', urlreg.test(url) == false)
});

$('textarea').trigger('input');
textarea{color:green;}
.invalid{color:red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>http://www.google.com</textarea>
<textarea>http//www.google.com</textarea>
<textarea>googlecom</textarea>
<textarea>https://www.google.com</textarea>

บทความ Wikipedia: รายการโดเมนระดับบนสุดของอินเทอร์เน็ตทั้งหมด


ใครช่วยแปลงนี้เพื่อใช้ใน Javascript?
user1063287

ในที่สุด !! ใครสามารถทำเครื่องหมายคำตอบนี้เป็นคำตอบได้ไหม หรือที่เช่า upvote มัน สิ่งที่ฉัน t.coแต่ฉันไม่คิดว่ามันตรงกับโดเมนตัวอักษรเดียวคือ คุณจะปรับมันเพื่อรับมือกับกรณีเหล่านี้อย่างไร?
Alkasai

ดูเหมือนว่าจะอนุญาต http // โดย:
AwokeKnowing

จับคู่หมายเลขโทรศัพท์และที่อยู่อีเมลมีลักษณะที่regexr.com/3eosrคัดลอกวาง regex ของคุณเพียงแค่ slashes ทั้งหมด
Can Rau

11

นิพจน์ปกติที่ดีที่สุดสำหรับ URL สำหรับฉันจะเป็น:

"(([\w]+:)?//)?(([\d\w]|%[a-fA-F\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?"

ดูเหมือนว่าจะมีการ จำกัด จำนวนโดเมนที่จะรับได้
rektide

2
ขอบคุณ! นี่คือเวอร์ชั่นหลบหนีที่ทำงานให้ฉันบน iOS:(([\\w]+:)?//)?(([\\d\\w]|%[a-fA-f\\d]{2,2})+(:([\\d\\w]|%[a-fA-f\\d]{2,2})+)?@)?([\\d\\w][-\\d\\w]{0,253}[\\d\\w]\\.)+[\\w]{2,4}(:[\\d]+)?(/([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})*)*(\\?(&?([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})=?)*)?(#([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})*)?
James Kuang

regex นี้จะจับคู่ส่วนต่อท้ายที่ยาวไม่เกิน 4 อักขระและล้มเหลวในที่อยู่ IP (v4 และ v6), localhost และชื่อโดเมนที่มีอักขระต่างประเทศ ฉันขอแนะนำให้แก้ไขช่วงการรวมขนาดของคุณและแทนที่\wด้วย\p{L}อย่างน้อยที่สุด
ndm13

โปรดทราบว่า RegEx นี้ไม่ได้จับ URL ที่มีโดเมนย่อยของตัวอักษรหนึ่งตัวเท่านั้นเช่น" m.sitename.com " เพื่อแก้ไขปัญหานั้นฉันต้องเปลี่ยน([\d\w][-\d\w]{0,253}[\d\w]\.)+เป็น([\d\w][-\d\w]{0,253}[\d\w]?\.)+(เพิ่มเครื่องหมายคำถามใกล้ถึงจุดสิ้นสุด)
Yoav Feuerstein

9
        function validateURL(textval) {
            var urlregex = new RegExp(
            "^(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*$");
            return urlregex.test(textval);
        }

จับคู่ http://site.com/dir/file.php?var=moo | ftp: // ผู้ใช้: pass@site.com: 21 / ไฟล์ / dir

ไซต์ที่ไม่ตรงกับ | http://site.com/dir//


โปรดทราบว่า regex นี้จะจับคู่หากเรามี [empty space] ใน url ตัวอย่าง: http://www.goo gle.comจะจับคู่
Ifch0o1

ใช้ parse_url () ก่อนที่จะเรียกใช้ฟังก์ชันนี้
user1524615

อย่าลืมที่จะหลบหนี "/" และ "?" ซึ่งเป็นแนวปฏิบัติที่ดีและควรทำให้มันเข้ากันได้ (จากสิ่งที่ฉันรู้ (ซึ่งไม่มากในเรื่องนี้ :)))
Steve P


7

ฉันไม่สามารถค้นหา regex ที่ฉันต้องการได้ดังนั้นฉันจึงปรับเปลี่ยน regex เพื่อเติมเต็มความต้องการของฉันและดูเหมือนว่ามันจะทำงานได้ดีในตอนนี้ ความต้องการของฉันคือ:

  • จับคู่ URL โดยไม่มีโปรโตคอล (www.gooogle.com)
  • จับคู่ URL กับพารามิเตอร์การสืบค้นและเส้นทาง ( http://subdomain.web-site.com/cgi-bin/perl.cgi?key1=value1&key2=value2e )
  • อย่าจับคู่ URL ที่ไม่มีอักขระที่ยอมรับได้ (เช่น "'£) ตัวอย่างเช่น: (www.google.co.th/somthing"/somethingmore)

นี่คือสิ่งที่ฉันคิดขึ้นมาข้อเสนอแนะใด ๆ ที่ได้รับการชื่นชม:

@Test
    public void testWebsiteUrl(){
        String regularExpression = "((http|ftp|https):\\/\\/)?[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?";

        assertTrue("www.google.com".matches(regularExpression));
        assertTrue("www.google.co.uk".matches(regularExpression));
        assertTrue("http://www.google.com".matches(regularExpression));
        assertTrue("http://www.google.co.uk".matches(regularExpression));
        assertTrue("https://www.google.com".matches(regularExpression));
        assertTrue("https://www.google.co.uk".matches(regularExpression));
        assertTrue("google.com".matches(regularExpression));
        assertTrue("google.co.uk".matches(regularExpression));
        assertTrue("google.mu".matches(regularExpression));
        assertTrue("mes.intnet.mu".matches(regularExpression));
        assertTrue("cse.uom.ac.mu".matches(regularExpression));

        assertTrue("http://www.google.com/path".matches(regularExpression));
        assertTrue("http://subdomain.web-site.com/cgi-bin/perl.cgi?key1=value1&key2=value2e".matches(regularExpression));
        assertTrue("http://www.google.com/?queryparam=123".matches(regularExpression));
        assertTrue("http://www.google.com/path?queryparam=123".matches(regularExpression));

        assertFalse("www..dr.google".matches(regularExpression));

        assertFalse("www:google.com".matches(regularExpression));

        assertFalse("https://www@.google.com".matches(regularExpression));

        assertFalse("https://www.google.com\"".matches(regularExpression));
        assertFalse("https://www.google.com'".matches(regularExpression));

        assertFalse("http://www.google.com/path'".matches(regularExpression));
        assertFalse("http://subdomain.web-site.com/cgi-bin/perl.cgi?key1=value1&key2=value2e'".matches(regularExpression));
        assertFalse("http://www.google.com/?queryparam=123'".matches(regularExpression));
        assertFalse("http://www.google.com/path?queryparam=12'3".matches(regularExpression));

    }

+1 รักเมื่อมีคนเพิ่มกรณีทดสอบ มันง่ายมากที่จะทำให้ลูกตามากกว่าที่จะพยายามถอดรหัส regex ทันที
Dawid O

7

หากคุณค้นหาการจับคู่ที่ดีที่สุดจริงๆคุณอาจพบมันใน " A Good Url Regular Expression? "

แต่ regex ที่ตรงกับโดเมนที่เป็นไปได้ทั้งหมดและอนุญาตสิ่งใดก็ตามที่ได้รับอนุญาตตาม RFCs นั้นยาวและน่าอ่านไม่น่าเชื่อถือเชื่อฉัน ;-)


5

ฉันทำงานเกี่ยวกับบทความเชิงลึกเกี่ยวกับการตรวจสอบความถูกต้องของ URI โดยใช้นิพจน์ทั่วไป มันขึ้นอยู่กับ RFC3986

การตรวจสอบ URI ของนิพจน์ปกติ

แม้ว่าบทความจะยังไม่เสร็จสมบูรณ์ แต่ฉันได้รับฟังก์ชั่น PHP ซึ่งทำงานได้ค่อนข้างดีในการตรวจสอบความถูกต้องของ HTTP และ FTP URL นี่คือรุ่นปัจจุบัน:

// function url_valid($url) { Rev:20110423_2000
//
// Return associative array of valid URI components, or FALSE if $url is not
// RFC-3986 compliant. If the passed URL begins with: "www." or "ftp.", then
// "http://" or "ftp://" is prepended and the corrected full-url is stored in
// the return array with a key name "url". This value should be used by the caller.
//
// Return value: FALSE if $url is not valid, otherwise array of URI components:
// e.g.
// Given: "http://www.jmrware.com:80/articles?height=10&width=75#fragone"
// Array(
//    [scheme] => http
//    [authority] => www.jmrware.com:80
//    [userinfo] =>
//    [host] => www.jmrware.com
//    [IP_literal] =>
//    [IPV6address] =>
//    [ls32] =>
//    [IPvFuture] =>
//    [IPv4address] =>
//    [regname] => www.jmrware.com
//    [port] => 80
//    [path_abempty] => /articles
//    [query] => height=10&width=75
//    [fragment] => fragone
//    [url] => http://www.jmrware.com:80/articles?height=10&width=75#fragone
// )
function url_valid($url) {
    if (strpos($url, 'www.') === 0) $url = 'http://'. $url;
    if (strpos($url, 'ftp.') === 0) $url = 'ftp://'. $url;
    if (!preg_match('/# Valid absolute URI having a non-empty, valid DNS host.
        ^
        (?P<scheme>[A-Za-z][A-Za-z0-9+\-.]*):\/\/
        (?P<authority>
          (?:(?P<userinfo>(?:[A-Za-z0-9\-._~!$&\'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?
          (?P<host>
            (?P<IP_literal>
              \[
              (?:
                (?P<IPV6address>
                  (?:                                                (?:[0-9A-Fa-f]{1,4}:){6}
                  |                                                ::(?:[0-9A-Fa-f]{1,4}:){5}
                  | (?:                          [0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}
                  | (?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}
                  | (?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}
                  | (?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::   [0-9A-Fa-f]{1,4}:
                  | (?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::
                  )
                  (?P<ls32>[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}
                  | (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
                       (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
                  )
                |   (?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::   [0-9A-Fa-f]{1,4}
                |   (?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::
                )
              | (?P<IPvFuture>[Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&\'()*+,;=:]+)
              )
              \]
            )
          | (?P<IPv4address>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
                               (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
          | (?P<regname>(?:[A-Za-z0-9\-._~!$&\'()*+,;=]|%[0-9A-Fa-f]{2})+)
          )
          (?::(?P<port>[0-9]*))?
        )
        (?P<path_abempty>(?:\/(?:[A-Za-z0-9\-._~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)
        (?:\?(?P<query>       (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
        (?:\#(?P<fragment>    (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
        $
        /mx', $url, $m)) return FALSE;
    switch ($m['scheme']) {
    case 'https':
    case 'http':
        if ($m['userinfo']) return FALSE; // HTTP scheme does not allow userinfo.
        break;
    case 'ftps':
    case 'ftp':
        break;
    default:
        return FALSE;   // Unrecognized URI scheme. Default to FALSE.
    }
    // Validate host name conforms to DNS "dot-separated-parts".
    if ($m['regname']) { // If host regname specified, check for DNS conformance.
        if (!preg_match('/# HTTP DNS host name.
            ^                      # Anchor to beginning of string.
            (?!.{256})             # Overall host length is less than 256 chars.
            (?:                    # Group dot separated host part alternatives.
              [A-Za-z0-9]\.        # Either a single alphanum followed by dot
            |                      # or... part has more than one char (63 chars max).
              [A-Za-z0-9]          # Part first char is alphanum (no dash).
              [A-Za-z0-9\-]{0,61}  # Internal chars are alphanum plus dash.
              [A-Za-z0-9]          # Part last char is alphanum (no dash).
              \.                   # Each part followed by literal dot.
            )*                     # Zero or more parts before top level domain.
            (?:                    # Explicitly specify top level domains.
              com|edu|gov|int|mil|net|org|biz|
              info|name|pro|aero|coop|museum|
              asia|cat|jobs|mobi|tel|travel|
              [A-Za-z]{2})         # Country codes are exactly two alpha chars.
              \.?                  # Top level domain can end in a dot.
            $                      # Anchor to end of string.
            /ix', $m['host'])) return FALSE;
    }
    $m['url'] = $url;
    for ($i = 0; isset($m[$i]); ++$i) unset($m[$i]);
    return $m; // return TRUE == array of useful named $matches plus the valid $url.
}

ฟังก์ชั่นนี้ใช้ประโยชน์สอง regexes; หนึ่งรายการเพื่อจับคู่ชุดย่อยของ URIs ทั่วไปที่ถูกต้อง (รายการที่แน่นอนมีโฮสต์ที่ไม่ว่าง) และอีกหนึ่งวินาทีเพื่อตรวจสอบชื่อโฮสต์ DNS "dot-split-parts" แม้ว่าฟังก์ชั่นนี้จะตรวจสอบความถูกต้องของ HTTP และ FTP เท่านั้น แต่มันมีโครงสร้างที่สามารถขยายได้อย่างง่ายดายเพื่อจัดการกับรูปแบบอื่น ๆ


ฉันอยากรู้ว่าทำไมคุณเลือกที่จะติดตาม URI RFC3986 มากกว่า IRI RFC3987
เปลือกตา

@eyelidlessness - เป็นคำถามที่ดี ฉันไม่ค่อยเชี่ยวชาญเรื่อง IRIs ขอบคุณที่ชี้ให้เห็นว่า RFC ฉันเห็นว่าตาม RFC3987: "... ในโปรโตคอล HTTP [RFC2616] Request URI ถูกกำหนดเป็น URI ซึ่งหมายความว่าไม่อนุญาตให้ใช้ IRIs โดยตรงในคำขอ HTTP" ดังนั้น IRI จึงถูกเข้ารหัสเป็น URI ก่อนส่งผ่าน HTTP ดังนั้นในขณะนี้จะมีความจำเป็นในการตรวจสอบ URI เสมอ บางทีฉันจะแก้ไขปัญหาการตรวจสอบ IRI ในภายหลัง ขอบคุณสำหรับความคิดเห็น!
ridgerunner

@ridgerunner การอ้างอิงถึง 2616 นั้นล้าสมัยแล้ว IRIs ถูกส่งเป็น IRIs โดยมีอักขระทั้งหมดที่ IRIs อนุญาตและ URI ไม่ได้ ฉันขอขอบคุณความพยายามที่จะสร้างรูปแบบ "ที่มนุษย์อ่านได้" (และฉันได้ทำงานด้วยตัวเอง แต่ไม่ได้มีโอกาสทดสอบอย่างเพียงพอ) แต่ในปี 2012 และในปี 2013 การเข้าสู่ปี 2013 เป็นเรื่องที่ยอมรับไม่ได้ อันที่จริงแล้วตัวอักษรตะวันตกนั้นมีการใช้งานอย่างกว้างขวางในเส้นทางชิ้นส่วนและแม้กระทั่งโดเมน
เปลือกตา

@eyelidlessness - ฉันคิดว่าฉันต้องดูอย่างใกล้ชิดในเรื่องนี้ ขอบคุณสำหรับหัวขึ้น.
ridgerunner

@ridgerunner, ไชโย! และฉันขอโทษถ้าฉันออกมาเป็นคนหยาบคายฉันไม่ควรแสดงความคิดเห็นหลังจากดื่ม! ฉันปรบมือให้ความพยายามที่จะทำให้รูปแบบที่มนุษย์อ่านได้และคุณมี upvote ของฉัน
เปลือกตา

5

ฉันเขียนรุ่น groovy เล็กน้อยที่คุณสามารถเรียกใช้

มันตรงกับ URL ต่อไปนี้ (ซึ่งดีพอสำหรับฉัน)

public static void main(args){
        String url = "go to http://www.m.abut.ly/abc its awesome"
        url = url.replaceAll(/https?:\/\/w{0,3}\w*?\.(\w*?\.)?\w{2,3}\S*|www\.(\w*?\.)?\w*?\.\w{2,3}\S*|(\w*?\.)?\w*?\.\w{2,3}[\/\?]\S*/ , { it ->
            "woof${it}woof"
        })
        println url

    }

http://google.com

http://google.com/help.php

http://google.com/help.php?a=5

http://www.google.com

http://www.google.com/help.php

http://www.google.com?a=5

google.com?a=5

google.com/help.php

google.com/help.php?a=5

http://www.m.google.com/help.php?a=5 (และการเปลี่ยนลำดับทั้งหมด)

www.m.google.com/help.php?a=5 (และการเรียงสับเปลี่ยนทั้งหมด)

m.google.com/help.php?a=5 (และการเปลี่ยนลำดับทั้งหมด)

สิ่งสำคัญสำหรับ URL ใด ๆ ที่ไม่ได้ขึ้นต้นด้วย http หรือ www คือต้องมี / หรือ?

ฉันคิดว่ามันน่าจะดีกว่านี้นิดหน่อย แต่มันก็ใช้งานได้ดีเพราะสั้นและกะทัดรัด ... เพราะคุณสามารถแยกมันออกเป็น 3:

ค้นหาสิ่งที่เริ่มต้นด้วย http: https?: // w {0,3} \ w *?. \ w {2,3} \ S *

ค้นหาสิ่งที่เริ่มต้นด้วย www: www. \ w *?. \ w {2,3} \ S *

หรือค้นหาสิ่งที่ต้องมีข้อความตามด้วยจุดแล้วอย่างน้อย 2 ตัวอักษรและจากนั้น? หรือ /: \ w *?. \ w {2,3} [/ \?] \ S *


1
สิ่งนี้ไม่รองรับ-URL
nhahtdh

5

ฉันใช้ regex นี้:

((https?:)?//)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,63}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?

เพื่อรองรับทั้งสอง:

http://stackoverflow.com
https://stackoverflow.com

และ:

//stackoverflow.com

2
ฉันต้องอัพเดท regex ของคุณ ที่สาม '?' อนุญาตให้เลือกข้อความทุกประเภท หลังจากลบเฉพาะ 'http', 'https' หรือ '//' เท่านั้น ฉันแก้ไขสิ่งนี้เพื่อให้สามารถทำงานกับ URL ที่เกี่ยวข้องเป็น '/' และหนีไปข้างหน้าเครื่องหมายทับ ((https?:)?(\/?\/))(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,63}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?
Markus

1
อัปเดตกลุ่มจับภาพเพื่อให้มีประโยชน์มากขึ้น: ((?:https?:)?(?:\/?\/))((?:[\d\w]|%[a-fA-f\d]{2,2})+(?::(?:[\d\w]|%[a-fA-f\d]{2,2})+)?@)?((?:[\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,63})(:[\d]+)?(\/(?:[-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(?:&?(?:[-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#(?:[-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?
panec

5

นี่เป็นกฎที่ดีที่ครอบคลุมทุกกรณีที่เป็นไปได้: พอร์ต, params และอื่น ๆ

/(https?:\/\/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9])(:?\d*)\/?([a-z_\/0-9\-#.]*)\??([a-z_\/0-9\-#=&]*)/g

น่าเสียดายที่ URL นี้ไม่ครอบคลุมพารามิเตอร์ที่มีค่าที่เข้ารหัสเช่นrayliverified.com?url=https%3A%2F%2Fbing.com
Ray Li

4

อันนี้ใช้ได้ดีกับฉันมาก (https?|ftp)://(www\d?|[a-zA-Z0-9]+)?\.[a-zA-Z0-9-]+(\:|\.)([a-zA-Z0-9.]+|(\d+)?)([/?:].*)?


4

นี่คือเวอร์ชัน Java ที่พร้อมใช้งานจากซอร์สโค้ด Android นี่คือสิ่งที่ดีที่สุดที่ฉันได้พบ

public static final Matcher WEB  = Pattern.compile(new StringBuilder()                 
.append("((?:(http|https|Http|Https|rtsp|Rtsp):")                      
.append("\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)")                         
.append("\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_")                         
.append("\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?")                         
.append("((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+")   // named host                            
.append("(?:")   // plus top level domain                         
.append("(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])")                         
.append("|(?:biz|b[abdefghijmnorstvwyz])")                         
.append("|(?:cat|com|coop|c[acdfghiklmnoruvxyz])")                         
.append("|d[ejkmoz]")                         
.append("|(?:edu|e[cegrstu])")                         
.append("|f[ijkmor]")                         
.append("|(?:gov|g[abdefghilmnpqrstuwy])")                         
.append("|h[kmnrtu]")                         
.append("|(?:info|int|i[delmnoqrst])")                         
.append("|(?:jobs|j[emop])")                         
.append("|k[eghimnrwyz]")                         
.append("|l[abcikrstuvy]")                         
.append("|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])")                         
.append("|(?:name|net|n[acefgilopruz])")                         
.append("|(?:org|om)")                         
.append("|(?:pro|p[aefghklmnrstwy])")                         
.append("|qa")                         
.append("|r[eouw]")                         
.append("|s[abcdeghijklmnortuvyz]")                         
.append("|(?:tel|travel|t[cdfghjklmnoprtvwz])")                         
.append("|u[agkmsyz]")                         
.append("|v[aceginu]")                         
.append("|w[fs]")                         
.append("|y[etu]")                         
.append("|z[amw]))")                         
.append("|(?:(?:25[0-5]|2[0-4]") // or ip address                                                 
.append("[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]")                             
.append("|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]")                         
.append("[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}")                         
.append("|[1-9][0-9]|[0-9])))")                         
.append("(?:\\:\\d{1,5})?)") // plus option port number                             
.append("(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~")  // plus option query params                         
.append("\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?")                         
.append("(?:\\b|$)").toString()                 
).matcher("");

นี้จะไม่ได้ทำงานด้วย "ใหม่ gTLDs" ตรวจสอบen.wikipedia.org/wiki/List_of_Internet_top-level_domains & newgtlds.icann.org/en/program-status/delegated-strings รายการ Hardcoding ของ TLD เป็นแนวทางปฏิบัติที่ไม่ดี ... มีรายการส่วนต่อท้ายสาธารณะบางรายการซึ่งรวมถึงตัวแปร TLD ล่าสุด: publicsuffix.org (ใช้ใน Firefox, Chrome, IE)
osgx

ความคิดแรกของฉันเมื่อเห็นสิ่งนี้: ไม่มีการฆ่าที่เกินความต้องการ พวกเขาใช้เวลาทั้งหมด ccTLDs และสร้าง regex เพื่อให้ตรงกับพวกเขาโดยเฉพาะ ฉันคิดว่ามันเป็นการลดเชิงบวก แต่เป็นวิธีที่แย่มากในการจัดการกับสถานการณ์
ndm13

4

นี่คือ regex ที่ฉันทำซึ่งแยกส่วนต่าง ๆ จาก URL:

^((?:https?|ftp):\/\/?)?([^:/\s.]+\.[^:/\s]|localhost)(:\d+)?((?:\/\w+)*\/)?([\w\-.]+[^#?\s]+)?([^#]+)?(#[\w-]+)?$

((?:https?|ftp):\/\/?)?(กลุ่ม 1) : แยกโปรโตคอล
([^:/\s.]+\.[^:/\s]|localhost)(กลุ่ม 2) : แยกชื่อโฮสต์
(:\d+)?(กลุ่ม 3) : แยกหมายเลขพอร์ต
((?:\/\w+)*\/)?([\w\-.]+[^#?\s]+)?(กลุ่ม 4 และ 5) : แยกส่วนเส้นทาง
([^#]+)?(กลุ่ม 6) : แยกส่วนแบบสอบถาม
(#[\w-]+)?(กลุ่ม 7) : แยกส่วนแฮช

สำหรับทุกส่วนของ regex ที่ระบุไว้ข้างต้นคุณสามารถลบจุดสิ้นสุด?เพื่อบังคับ (หรือเพิ่มส่วนหนึ่งเพื่อทำให้เป็นแบบปัญญา) นอกจากนี้คุณยังสามารถลบ^จุดเริ่มต้นและ$จุดสิ้นสุดของ regex ดังนั้นจึงไม่จำเป็นต้องตรงกับสตริงทั้งหมด

เห็นมันบนregex101

หมายเหตุ: regex นี้ไม่ปลอดภัย 100% และอาจยอมรับสตริงที่ไม่จำเป็นต้องมี URL ที่ถูกต้อง แต่มันจะตรวจสอบความถูกต้องของเกณฑ์บางอย่าง เป้าหมายหลักคือเพื่อแยกส่วนต่าง ๆ ของ URL ที่จะไม่ตรวจสอบ


ขอบคุณ วิธีการแบบกลุ่มของคำตอบเหล่านี้ดีที่สุด หวังว่าจะมีการอัปเดตตามทิศทางของบทความนี้ที่เชื่อมโยงในหน้าถัดไปและการแก้ไข "ไม่ปลอดภัย 100%" ปริมาณเช่น 99.9% ก็เพียงพอสำหรับผู้อ่านส่วนใหญ่ : P
Laurie Stearn

3

สำหรับ Python นี่คือ URL จริงที่ตรวจสอบ regex ที่ใช้ใน Django 1.5.1:

import re
regex = re.compile(
        r'^(?:http|ftp)s?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|'  # ...or ipv4
        r'\[?[A-F0-9]*:[A-F0-9:]+\]?)'  # ...or ipv6
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)

สิ่งนี้ทำทั้งที่อยู่ ipv4 และ ipv6 รวมถึงพอร์ตและพารามิเตอร์ GET

พบในรหัสที่นี่บรรทัดที่ 44


3

ฉันพบ Regex ต่อไปนี้สำหรับ URL ทดสอบกับ URL มากกว่า 500+ เรียบร้อยแล้ว :

/\b(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\b/gi

ฉันรู้ว่ามันดูน่าเกลียด แต่สิ่งที่ดีคือมันใช้งานได้ :)

คำอธิบายและการสาธิตด้วย581 URL สุ่มบน regex101

ที่มา: ในการค้นหา regex การตรวจสอบความถูกต้องของ URL ที่สมบูรณ์แบบ


3
regex ของคุณกำลังทำงานอยู่ใน 155'000 ขั้นตอน นี่คืออีก regex ที่มีการประเมินทั้งหมด 580 URL ที่คุณระบุใน 19'000 ขั้นตอนregex101 ลิงค์ :/(https?):\/\/([\w-]+(\.[\\w-]+)*\.([a-z]+))(([\w.,@?^=%&amp;:\/~+#()!-]*)([\w@?^=%&amp;\/~+#()!-]))?/gi
Jonathan Maim

2

ฉันพยายามกำหนด URL เวอร์ชันของฉัน ความต้องการของฉันคือการจับภาพอินสแตนซ์ในสตริงที่ URL ที่เป็นไปได้สามารถ cse.uom.ac.mu - สังเกตว่ามันไม่ได้นำหน้าด้วย http หรือ www

String regularExpression = "((((ht{2}ps?://)?)((w{3}\\.)?))?)[^.&&[a-zA-Z0-9]][a-zA-Z0-9.-]+[^.&&[a-zA-Z0-9]](\\.[a-zA-Z]{2,3})";

assertTrue("www.google.com".matches(regularExpression));
assertTrue("www.google.co.uk".matches(regularExpression));
assertTrue("http://www.google.com".matches(regularExpression));
assertTrue("http://www.google.co.uk".matches(regularExpression));
assertTrue("https://www.google.com".matches(regularExpression));
assertTrue("https://www.google.co.uk".matches(regularExpression));
assertTrue("google.com".matches(regularExpression));
assertTrue("google.co.uk".matches(regularExpression));
assertTrue("google.mu".matches(regularExpression));
assertTrue("mes.intnet.mu".matches(regularExpression));
assertTrue("cse.uom.ac.mu".matches(regularExpression));

//cannot contain 2 '.' after www
assertFalse("www..dr.google".matches(regularExpression));

//cannot contain 2 '.' just before com
assertFalse("www.dr.google..com".matches(regularExpression));

// to test case where url www must be followed with a '.'
assertFalse("www:google.com".matches(regularExpression));

// to test case where url www must be followed with a '.'
//assertFalse("http://wwwe.google.com".matches(regularExpression));

// to test case where www must be preceded with a '.'
assertFalse("https://www@.google.com".matches(regularExpression));

12
คุณจะใช้จริง ๆht{2}ps?แล้วhttps?
Roee Gavirel

2
มันควรให้ผลลัพธ์เดียวกัน แต่ใช่คุณพูดถูก แต่ฉันอยู่ในช่วงทดลองของนิพจน์ทั่วไปและต้องการลองใช้ไวยากรณ์ทั้งหมด ขอบคุณที่ชี้นำสิ่งนี้
Ashish

คุณสามารถช่วยฉันจัดทำ regex เช่นนี้ที่ตรงกับพารามิเตอร์การค้นหาและเส้นทางอื่น ๆ ได้หรือไม่ เช่น "www.awebsite.com/path?param=value"
thermz

2

มีอะไรผิดปกติกับ FILTER_VALIDATE_URL แบบธรรมดาหรือแบบง่าย

 $url = "http://www.example.com";

if(!filter_var($url, FILTER_VALIDATE_URL))
  {
  echo "URL is not valid";
  }
else
  {
  echo "URL is valid";
  }

ฉันรู้ว่ามันไม่ใช่คำถามอย่างแน่นอน แต่มันทำงานให้ฉันเมื่อฉันต้องการตรวจสอบ URL ดังนั้นจึงคิดว่ามันอาจเป็นประโยชน์กับคนอื่นที่เจอโพสต์นี้ที่กำลังมองหาสิ่งเดียวกัน


1
คำถามนี้กำลังมองหา regexp แต่คุณแนะนำให้ใช้ค่าคงที่ตัวกรอง คุณรู้หรือไม่ว่ามันค้นหาลิงก์ภายในได้อย่างไร
Kuitsi

คำถามคือ: "นิพจน์ทั่วไปที่ดีที่สุดในการตรวจสอบว่าสตริงเป็น URL ที่ถูกต้องคืออะไร" บางครั้งปัญหาไม่ได้ตรวจสอบ String ที่ควรจะเป็น URL บางครั้งคุณมีข้อความและคุณจำเป็นต้องอ่าน URL ทั้งหมดในข้อความนั้นและการใช้ REGEX เป็นวิธีเดียวเท่านั้น นอกจากนี้ OP ขอคำตอบโดยไม่ระบุภาษาใดภาษาหนึ่งโซลูชันของคุณสามารถใช้งานได้ในแพลตฟอร์มเฉพาะเท่านั้น
ร้อน


2

ใช้อันนี้มันทำงานสำหรับฉัน

function validUrl(Url) {
    var myRegExp  =/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;

    if (!RegExp.test(Url.value)) {
        $("#urlErrorLbl").removeClass('highlightNew');
        return false;
    } 

    $("#urlErrorLbl").addClass('highlightNew'); 
    return true; 
}

2

เพื่อความสะดวกนี่คือ regexp แบบหนึ่งเดียวสำหรับ URL ที่จะจับคู่โลคัลโฮสต์ที่คุณมีแนวโน้มที่จะมีพอร์ตมากกว่า.comหรือคล้ายกัน

(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6}|:[0-9]{3,4})\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)

2

คุณไม่ได้ระบุภาษาที่คุณใช้ ถ้า PHP คือนั่นคือฟังก์ชั่นพื้นเมืองสำหรับที่:

$url = 'http://www.yoururl.co.uk/sub1/sub2/?param=1&param2/';

if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
    // Wrong
}
else {
    // Valid
}

ส่งคืนข้อมูลที่กรองแล้วหรือเป็น FALSE หากตัวกรองล้มเหลว

ตรวจสอบที่นี่ >>

หวังว่ามันจะช่วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.