Regex เท่ากับ n หรือ m เท่า


105

พิจารณาการแสดงออกปกติต่อไปนี้ที่Xเป็นใด ๆ regex

X{n}|X{m}

regex นี้จะทดสอบว่าXเกิดขึ้นตรง nหรือmเวลา

มีปริมาณ regex ที่สามารถทดสอบการเกิดขึ้นXตรงnหรือmครั้ง?


เลขที่ปรากฏของสองXที่ดีที่สุดคือคุณจะได้รับโดยทั่วไป,m n
John Dvorak

ถ้านี่เป็นปัญหาของฉันฉันจะลอง backreferences regex (X)\1{n-1}(?:\1{m-n-1})และจะเริ่มต้นด้วย ฉันรู้ว่าแมตช์นี้Xอย่างน้อยหนึ่งครั้ง แต่เพียงการเริ่มต้นลองสิ่งที่ง่ายนี้แล้วสินค้าโดยใช้ lookaheads หรือ lookbehinds (X)แทน
nalply

คำตอบ:


91

ไม่มีตัวบ่งชี้เดียวที่หมายถึง "m หรือ n คูณ" วิธีที่คุณกำลังทำอยู่นั้นดี

อีกทางเลือกหนึ่งคือ:

X{m}(X{k})?

ที่ไหนm < nและkค่าของn-m.


67

นี่คือรายการตัวบ่งชี้ทั้งหมด (อ้างอิงhttp://www.regular-expressions.info/reference.html ):

  • ?, ??- 0 หรือ 1 ครั้ง ( ??ขี้เกียจ, ?โลภ)
  • *, *?- จำนวนครั้งที่เกิดขึ้น
  • +, +?- อย่างน้อยหนึ่งครั้ง
  • {n}- nเกิดขึ้นอย่างแน่นอน
  • {n,m}- ที่nจะmเกิดขึ้นรวม
  • {n,m}?- nจะmปรากฏขี้เกียจ
  • {n,}, {n,}?- อย่างน้อยก็nเกิดขึ้น

ในการรับ "N หรือ M" คุณต้องเขียน regex เชิงปริมาณสองครั้งเว้นแต่ m, n จะพิเศษ:

  • X{n,m} ถ้า m = n+1
  • (?:X{n}){1,2} ถ้า m = 2n
  • ...

1
เหตุใดจึง?:จำเป็นต้องมีในm = 2nตัวอย่างif ดูเหมือนจะทำงานได้ดีถ้าไม่มีฉัน
erb

7
@erb ถ้าคุณออกไป?:กลุ่มจะกลายเป็นกลุ่มที่จับได้ นอกเหนือจากเอนจิน regex ที่จำสิ่งต่างๆแล้วไม่จำเป็นต้องทำหากคุณมีการจับกลุ่มหลังจากกลุ่มนี้ ID ของพวกเขาจะเปลี่ยนไป หากคุณใช้นิพจน์ทั่วไปในการแทนที่คุณจะต้องปรับเปลี่ยนการแทนที่
John Dvorak

19

ไม่ไม่มีตัวระบุจำนวนดังกล่าว แต่ฉันต้องการปรับโครงสร้างมัน/X{m}(X{m-n})?/เพื่อป้องกันไม่ให้เกิดปัญหาในการย้อนรอย


3

TLDR; (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

ดูเหมือนว่าคุณต้องการ "xn times" หรือ "xm times" ฉันคิดว่าการแปลตามตัวอักษรเป็น regex จะเป็น(x{n}|x{m}). เช่นนี้ https://regex101.com/r/vH7yL5/1

หรือในกรณีที่คุณสามารถมีลำดับของมากกว่า m "x" วินาที (สมมติม> n) คุณสามารถเพิ่ม 'ต่อไปนี้ไม่มี 'x'' และ 'ตามด้วยไม่มี 'x' แปล[^x](x{n}|x{m})[^x]แต่ที่จะ สมมติว่ามีอักขระอยู่ข้างหลังและหลังคุณ "x" s เสมอ ดังที่คุณเห็นที่นี่: https://regex101.com/r/bB2vH2/1

คุณสามารถเปลี่ยนเป็น(?:[^x]|^)(x{n}|x{m})(?:[^x]|$)แปลเป็น "ต่อท้ายไม่ 'x' หรือต่อท้ายบรรทัดเริ่มต้น" และ "ตามด้วยไม่ 'x' หรือตามด้วยท้ายบรรทัด" แต่ถึงกระนั้นมันจะไม่จับคู่สองลำดับที่มีเพียงอักขระเดียวระหว่างพวกเขา (เนื่องจากการจับคู่ครั้งแรกจะต้องใช้อักขระหลังและอักขระที่สองก่อน) ดังที่คุณเห็นที่นี่: https://regex101.com/r/ oC5oJ4 / 1

สุดท้ายเพื่อให้ตรงกับการจับคู่ระยะห่างของอักขระหนึ่งตัวคุณสามารถเพิ่มการมองเชิงบวกไว้ข้างหน้า (? =) บน "ไม่ 'x' หลัง" หรือการมองเชิงบวกด้านหลัง (? <=) บน "ไม่ 'x' ก่อนหน้า", ดังนี้: https://regex101.com/r/mC4uX3/1

(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

วิธีนี้จะทำให้คุณจับคู่เฉพาะจำนวน "x ที่คุณต้องการเท่านั้น


1

เมื่อดูคำตอบของ Enhardened พวกเขาระบุว่าการแสดงออกสุดท้ายของพวกเขาจะไม่ตรงกับลำดับที่มีเพียงอักขระเดียวระหว่างพวกเขา มีวิธีง่ายๆในการแก้ไขปัญหานี้โดยไม่ต้องใช้ look ไปข้างหน้า / มองข้างหลังและนั่นคือการแทนที่อักขระเริ่มต้น / สิ้นสุดด้วยอักขระขอบเขต สิ่งนี้ช่วยให้คุณจับคู่กับขอบเขตคำซึ่งรวมถึงจุดเริ่มต้น / จุดสิ้นสุด ดังนั้นการแสดงออกที่เหมาะสมควรเป็น:

(?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)

ที่คุณสามารถดูที่นี่: https://regex101.com/r/oC5oJ4/2


1
เจ๋งฉันไม่คุ้นเคยกับวิธีจัดการกับขอบเขตของ regex ปัญหาเดียวของวิธีนี้คือเมื่อคุณใช้ขอบเขตที่ไม่ได้มาตรฐาน ลองดู: regex101.com/r/j0nkeo/1และregex101.com/r/4Ix7Dr/1
Enhardened

1
@Enhardened - นั่นเป็นจุดที่ดีดูเหมือนจะเป็นปัญหากับกลุ่มที่ตรงกันหลายกลุ่มที่ทับซ้อนกัน นั่นคือสถานการณ์ที่คุณต้องใช้การมองเบื้องหลัง
rozza2058

1

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

#[a-f0-9]{6}|#[a-f0-9]{3}

สิ่งนี้จะพบรหัสสีฐานสิบหกทั้งหมดที่เกิดขึ้น (มีความยาว 3 หรือ 6 หลัก) แต่พอพลิกไปมาแบบนี้

#[a-f0-9]{3}|#[a-f0-9]{6}

จะพบเฉพาะตัวเลข 3 หลักหรือ 3 หลักแรกของ 6 หลักเท่านั้น สิ่งนี้สมเหตุสมผลและ Regex pro อาจมองเห็นสิ่งนี้ได้ทันที แต่สำหรับหลาย ๆ คนสิ่งนี้อาจเป็นพฤติกรรมที่แปลกประหลาด มีคุณสมบัติขั้นสูงบางอย่างของ Regex ที่อาจหลีกเลี่ยงกับดักนี้ได้โดยไม่คำนึงถึงลำดับ แต่ไม่ใช่ทุกคนที่เจาะลึกถึงรูปแบบ Regex

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