อะไรคือความแตกต่างระหว่างวงเล็บเหลี่ยมและวงเล็บใน regex?


101

นี่คือนิพจน์ทั่วไปที่ฉันสร้างขึ้นเพื่อใช้ใน JavaScript:

var reg_num = /^(7|8|9)\d{9}$/

นี่คืออีกหนึ่งรายการที่แนะนำโดยสมาชิกในทีมของฉัน

var reg_num = /^[7|8|9][\d]{9}$/

กฎคือการตรวจสอบหมายเลขโทรศัพท์:

  • ควรเป็นตัวเลขเพียงสิบตัว
  • ตัวเลขแรกควรเป็น 7, 8 หรือ 9

คำตอบ:


124

regexes เหล่านี้เทียบเท่ากัน (เพื่อวัตถุประสงค์ในการจับคู่):

  • /^(7|8|9)\d{9}$/
  • /^[789]\d{9}$/
  • /^[7-9]\d{9}$/

คำอธิบาย:

  • (a|b|c)คือนิพจน์ทั่วไป "OR" และหมายถึง "a หรือ b หรือ c" แม้ว่าจะมีวงเล็บซึ่งจำเป็นสำหรับ OR แต่ก็จับตัวเลขด้วยเช่นกัน เพื่อให้เทียบเท่ากันอย่างเคร่งครัดคุณต้องเขียนโค้ด(?:7|8|9)เพื่อให้เป็นกลุ่มที่ไม่จับภาพ

  • [abc]คือ "คลาสอักขระ" ซึ่งหมายถึง "อักขระใด ๆ จาก a, b หรือ c" (คลาสอักขระอาจใช้ช่วงเช่น[a-d]= [abcd])

เหตุผลที่ regexes เหล่านี้มีความคล้ายคลึงกันคือคลาสอักขระเป็นชวเลขสำหรับ "หรือ" (แต่สำหรับอักขระเดี่ยวเท่านั้น) ในทางเลือกอื่นคุณยังสามารถทำสิ่ง(abc|def)ที่ไม่ได้แปลเป็นคลาสอักขระ


30
(7|8|9)และ[789]ไม่เทียบเท่าเพราะสิ่งแรกคือการจับภาพหลังไม่ใช่ (?:7|8|9)จะเทียบเท่าในทางกลับกัน (ฉันเดาว่าคุณรู้แน่นอน ... )
hochl

ฉันเห็น regex นี้: [<<|>>|\]\]|\[\[]. เพราะบริบทฉันรู้ regex ที่พยายามที่จะตรง<<หรือ>>หรือหรือ[[ ]]แต่จากสิ่งที่คุณได้กล่าวว่ามันควรจะมีการจับคู่<หรือ>หรือหรือ[ ]ถ้าคุณใช้|ระหว่าง[]วงเล็บจะทำงานต่างกันหรือไม่?
Daniel Kaplan

1
@DanielKaplan ไม่ใช้|ภายในคลาสอักขระ[...]เว้นแต่คุณต้องการจับคู่อักขระไปป์เอง นอกจากนี้การทำสำเนาอักขระในคลาสอักขระก็ไม่มีผลเช่นกันคลาสอักขระคือรายการของอักขระและจะจับคู่อักขระใดตัวหนึ่ง ฉันเดาว่าคุณต้องการกลุ่มซึ่งใช้วงเล็บกลมปกติ:(<<|>>|\]\]|\[\[)
โบฮีเมียน

57

คำแนะนำของทีมคุณเกือบจะถูกต้องยกเว้นความผิดพลาดที่เกิดขึ้น เมื่อคุณพบสาเหตุแล้วคุณจะไม่มีวันลืม ลองดูความผิดพลาดนี้

/^(7|8|9)\d{9}$/

สิ่งนี้ทำอะไร:

  • ^และ$หมายถึงการแข่งขันที่ยึดไว้ซึ่งยืนยันว่ารูปแบบย่อยระหว่างจุดยึดเหล่านี้เป็นการแข่งขันทั้งหมด สตริงจะจับคู่ก็ต่อเมื่อรูปแบบย่อยตรงกับทั้งหมดไม่ใช่เฉพาะส่วน
  • ()หมายถึงกลุ่มจับ
  • 7|8|9หมายถึงการจับคู่อย่างใดอย่างหนึ่ง7, หรือ8 9มันทำเช่นนี้กับทางเลือกซึ่งเป็นสิ่งที่ตัวดำเนินการท่อ|- สลับระหว่างทางเลือก การย้อนกลับระหว่างทางเลือกนี้: หากตัวเลือกแรกไม่ตรงกันเครื่องยนต์จะต้องกลับมาก่อนที่ตำแหน่งตัวชี้จะย้ายในระหว่างการจับคู่ของทางเลือกเพื่อดำเนินการจับคู่ตัวเลือกถัดไป ในขณะที่คลาสอักขระสามารถเลื่อนไปตามลำดับ ดูการจับคู่นี้ในเอนจิ้น regex ที่ปิดใช้งานการเพิ่มประสิทธิภาพ:
Pattern: (r|f)at
Match string: carat

ทางเลือก

Pattern: [rf]at
Match string: carat

ชั้นเรียน

  • \d{9}ตรงกับตัวเลขเก้าหลัก \dเป็นอักขระเมตาชวเลขซึ่งตรงกับตัวเลขใด ๆ
/^[7|8|9][\d]{9}$/

ดูว่ามันทำอะไร:

  • ^และ$หมายถึงการแข่งขันที่ยึดไว้เช่นกัน
  • [7|8|9]เป็นตัวละครคลาส ตัวอักษรใด ๆ จากรายการ7, |, 8, |หรือ9สามารถจับคู่จึง|ถูกบันทึกอยู่ในที่ไม่ถูกต้อง การจับคู่นี้ไม่มีการย้อนกลับ
  • [\d]เป็นตัวละครคลาสที่พรายน้ำ \dmetacharacter การผสมผสานระหว่างการใช้คลาสอักขระและอักขระเมตาเดียวเป็นความคิดที่ไม่ดีเนื่องจากเลเยอร์ของนามธรรมสามารถทำให้การจับคู่ช้าลงได้ แต่นี่เป็นเพียงรายละเอียดการนำไปใช้งานและใช้กับการใช้งาน regex เพียงไม่กี่รายการเท่านั้น JavaScript ไม่ใช่หนึ่งเดียว แต่ทำให้รูปแบบย่อยยาวขึ้นเล็กน้อย
  • {9} บ่งชี้ว่าโครงสร้างเดี่ยวก่อนหน้านี้ทำซ้ำทั้งหมดเก้าครั้ง

regex ที่ดีที่สุดคือ/^[789]\d{9}$/เนื่องจาก/^(7|8|9)\d{9}$/จับโดยไม่จำเป็นซึ่งทำให้ประสิทธิภาพการทำงานลดลงในการใช้งาน regex ส่วนใหญ่ (เกิดขึ้นเป็นหนึ่งเมื่อพิจารณาว่าคำถามใช้คำหลักvarในโค้ดซึ่งอาจเป็น JavaScript) การใช้ซึ่งทำงานบน PCRE สำหรับการจับคู่ preg จะเพิ่มประสิทธิภาพการไม่มีการย้อนกลับอย่างไรก็ตามเราไม่ได้อยู่ใน PHP เช่นกันดังนั้นการใช้คลาส[]แทนทางเลือก|จะให้โบนัสประสิทธิภาพเนื่องจากการจับคู่ไม่ย้อนกลับดังนั้นการจับคู่ทั้งสองและล้มเหลวเร็วกว่าการใช้ของคุณ นิพจน์ทั่วไปก่อนหน้านี้


6
ไม่ได้สนใจโปรแกรมอะไรภาพหน้าจอนั้นมาจาก?
Mr Mystery Guest

12

2 ตัวอย่างแรกทำหน้าที่แตกต่างกันมากหากคุณกำลังแทนที่ด้วยบางสิ่ง หากคุณตรงกับสิ่งนี้:

str = str.replace(/^(7|8|9)/ig,''); 

คุณจะแทนที่ 7 หรือ 8 หรือ 9 ด้วยสตริงว่าง

หากตรงกับสิ่งนี้

str = str.replace(/^[7|8|9]/ig,''); 

คุณจะเปลี่ยน7หรือ8หรือ9หรือแถบแนวตั้ง !!!! โดยสตริงว่าง

ฉันเพิ่งค้นพบวิธีนี้ยาก


6
ยินดีต้อนรับสู่ SO! การเปลี่ยนหรือจับคู่มันผิดธรรมดา ผู้คนจำนวนมากทำผิดพลาดนั้นและพวกเขามักจะหนีไปกับมันเป็นเวลาหลายปีบางครั้งเพราะสตริงอินพุตของพวกเขาไม่เคยมีไพพ์ ( |)
Alan Moore
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.