พื้นฐานนิพจน์ปกติ
นิพจน์ปกติ (regex) คือแพตเทิร์นที่ใช้อธิบายข้อความ คู่มือนี้ครอบคลุมองค์ประกอบพื้นฐานที่คุณจะใช้บ่อยที่สุด และข้อผิดพลาดที่ทำให้การจับคู่ช้าหรือได้ผลที่ไม่คาดคิด
อักขระตามตัวและคลาสอักขระ
อักขระส่วนใหญ่ตรงกับตัวมันเอง แพตเทิร์น cat จะพบข้อความ "cat" อักขระบางตัวมีความหมายพิเศษ เช่น . * + ? ( ) [ ] { } ^ $ | \ หากต้องการจับคู่อักขระเหล่านี้ตามตัวอักษร ให้ escape ด้วยแบ็กสแลช เช่น \. สำหรับจุด
คลาสอักขระจับคู่อักขระหนึ่งตัวจากชุดที่กำหนด [abc] ตรงกับ a, b หรือ c ส่วน [a-z] ตรงกับตัวอักษร ASCII พิมพ์เล็ก และ [^0-9] ตรงกับอะไรก็ได้ที่ไม่ใช่ตัวเลข รูปย่อที่ใช้บ่อยได้แก่ \d (ตัวเลข) \w (ตัวอักษร ตัวเลข หรือขีดล่าง) \s (ช่องว่าง) และรูปตรงข้าม \D, \W และ \S จุด . ตรงกับอักขระใดก็ได้ยกเว้นการขึ้นบรรทัดใหม่
ใน JavaScript \w และ \d ครอบคลุมเฉพาะอักขระ ASCII หากต้องการจับคู่ตัวอักษรของทุกภาษา ให้ใช้ Unicode property เช่น \p{L} ร่วมกับแฟล็ก u
ตัวระบุจำนวนและตัวยึดตำแหน่ง
ตัวระบุจำนวนบอกว่ารายการก่อนหน้าซ้ำได้กี่ครั้ง
| ไวยากรณ์ | ความหมาย | ตัวอย่าง |
|---|---|---|
* | 0 ครั้งขึ้นไป | ab* ตรงกับ a, ab, abbb |
+ | 1 ครั้งขึ้นไป | \d+ ตรงกับ 7 หรือ 2026 |
? | 0 หรือ 1 ครั้ง | colou?r ตรงกับ color และ colour |
{n,m} | ระหว่าง n ถึง m ครั้ง | \d{2,4} ตรงกับตัวเลข 2 ถึง 4 หลัก |
ตัวยึดตำแหน่งจับคู่ตำแหน่งแทนที่จะเป็นอักขระ ^ คือจุดเริ่มต้น และ $ คือจุดสิ้นสุดของข้อมูลเข้า (หรือของแต่ละบรรทัดเมื่อใช้แฟล็ก m) \b คือขอบคำ ดังนั้น \bcat\b จะพบ "cat" แต่ไม่พบใน "concatenate" เมื่อตรวจสอบค่าทั้งค่า ให้ยึดทั้งสองด้าน เช่น ^\d{5}$ รับเฉพาะตัวเลขห้าหลักพอดีเท่านั้น
กลุ่มและการจับ
วงเล็บใช้รวมส่วนหนึ่งของแพตเทิร์นเป็นกลุ่ม เพื่อให้ตัวระบุจำนวนหรือทางเลือกมีผลกับส่วนนั้น (ab)+ ทำซ้ำ "ab" และ (jpg|png) ตรงกับคำใดคำหนึ่ง กลุ่มปกติยังจับข้อความที่ตรงไว้ด้วย ซึ่งนำไปใช้ซ้ำในการแทนที่ได้เป็น $1, $2 และต่อไปเรื่อย ๆ
กลุ่มที่มีชื่อ เช่น (?<year>\d{4}) ทำให้แพตเทิร์นอ่านง่ายขึ้น และอ้างอิงได้เป็น $<year> หากต้องการเพียงการจัดกลุ่ม กลุ่มที่ไม่จับ (?:...) จะช่วยไม่ให้เกิดการจับที่ไม่ได้ใช้ เครื่องมือทดสอบ RegEx ของ LeedyBox แสดงส่วนที่ตรงแต่ละรายการพร้อมกลุ่มที่จับได้ และแสดงตัวอย่างการแทนที่
แฟล็ก
แฟล็กเปลี่ยนพฤติกรรมของทั้งแพตเทิร์น แฟล็กของ JavaScript ที่ใช้บ่อยได้แก่
g(global): ค้นหาทุกส่วนที่ตรง แทนที่จะหาเฉพาะส่วนแรกi(ignore case): ถือว่าตัวพิมพ์ใหญ่และตัวพิมพ์เล็กเหมือนกันm(multiline):^และ$ตรงที่การขึ้นบรรทัดใหม่แต่ละครั้งs(dotAll):.ตรงกับการขึ้นบรรทัดใหม่ด้วยu(unicode): เปิดใช้การจับคู่ที่รองรับ Unicode และคลาส\p{...}
JavaScript ยังมี y (sticky) และ d (ตำแหน่งของส่วนที่ตรง) ซึ่งเครื่องมือทดสอบก็รองรับเช่นกัน
Greedy กับ Lazy และ Catastrophic Backtracking
ตามค่าเริ่มต้น ตัวระบุจำนวนเป็นแบบ greedy คือจับคู่ให้มากที่สุดเท่าที่ทำได้ แล้วค่อยคืนอักขระทีละตัวหากส่วนที่เหลือของแพตเทิร์นไม่ตรง กับข้อความ <b>bold</b> แพตเทิร์น <.+> จะตรงกับทั้งสตริง การเติม ? ทำให้ตัวระบุจำนวนเป็นแบบ lazy ดังนั้น <.+?> จะตรงกับ <b> เพียงอย่างเดียว คลาสแบบปฏิเสธ เช่น <[^>]+> มักชัดเจนกว่าและเร็วกว่า
เอนจิน regex ส่วนใหญ่ รวมถึงของ JavaScript ใช้ backtracking ตัวระบุจำนวนซ้อนกันอย่าง (a+)+$ หรือทางเลือกที่ทับซ้อนกัน อาจทำให้เอนจินลองชุดค่าผสมจำนวนมหาศาลเมื่อจับคู่ไม่สำเร็จ ซึ่งอาจทำให้หน้าเว็บหรือเซิร์ฟเวอร์ค้าง ปัญหานี้เรียกว่า catastrophic backtracking และเมื่อใช้กับข้อมูลเข้าที่ไม่น่าเชื่อถือ อาจถูกนำไปใช้โจมตีแบบปฏิเสธการให้บริการ (ReDoS) ได้ หลีกเลี่ยงการซ้อนตัวระบุจำนวนบนอักขระชุดเดียวกัน เลือกใช้คลาสที่เจาะจงแทน .* และทดสอบแพตเทิร์นกับข้อมูลเข้ายาว ๆ ที่ไม่ตรง
Regex แต่ละแบบต่างกัน
regex ไม่มีมาตรฐานเดียว JavaScript, Python, Java, .NET, PCRE (ที่ PHP ใช้), Go และฐานข้อมูลต่าง ๆ รองรับไวยากรณ์ที่ต่างกันเล็กน้อย lookbehind, possessive quantifier, ไวยากรณ์กลุ่มที่มีชื่อ คลาส Unicode และไวยากรณ์การแทนที่แตกต่างกันไป ตัวอย่างเช่น เอนจิน RE2 ของ Go ไม่รองรับ lookaround และการอ้างอิงย้อนกลับ
เครื่องมือทดสอบ RegEx ของ LeedyBox ใช้เอนจิน JavaScript ของเบราว์เซอร์ แพตเทิร์นที่ใช้ได้ที่นั่นอาจต้องปรับแก้ในภาษาอื่น จึงควรทดสอบอีกครั้งในที่ที่จะรันจริง
คำถามที่พบบ่อย
ทำไมแพตเทิร์นของฉันจึงตรงเฉพาะตำแหน่งแรก
หากไม่มีแฟล็ก g JavaScript จะหยุดหลังจากพบส่วนที่ตรงส่วนแรก ให้เปิดแฟล็ก g เพื่อค้นหาทุกส่วนที่ตรง
regex ตรวจสอบที่อยู่อีเมลได้หรือไม่
regex ตรวจได้ว่าค่ามีลักษณะที่เป็นไปได้หรือไม่ แต่ยืนยันไม่ได้ว่าที่อยู่นั้นมีอยู่จริง วิธีที่ใช้กันทั่วไปในการยืนยันคือการส่งอีเมลยืนยัน
ทำไม ^ จึงตรงเพียงครั้งเดียวในข้อความหลายบรรทัด
ตามค่าเริ่มต้น ^ และ $ หมายถึงข้อมูลเข้าทั้งหมด ให้เปิดแฟล็ก m เพื่อให้ตรงที่ต้นและท้ายของแต่ละบรรทัด