การอ้างอิงที่มีสิทธิ์ในปัญหาในทางปฏิบัติที่อยู่เบื้องหลังการใช้เครื่องมือ regex คือชุดของสามบล็อกโพสต์โดยรัสคอคส์ ตามที่อธิบายไว้ที่นั่นตั้งแต่ backreferences ทำให้ภาษาของคุณไม่ปกติพวกเขาจะดำเนินการโดยใช้ย้อนรอย
Lookaheads และ lookbehinds เช่นคุณลักษณะหลายอย่างของเครื่องมือจับคู่รูปแบบ regex ไม่เหมาะกับกระบวนทัศน์ของการตัดสินใจว่าสตริงนั้นเป็นสมาชิกของภาษาหรือไม่ แทนที่จะใช้ regexes เรามักจะค้นหาสตริงย่อยภายในสตริงที่ใหญ่กว่า "การจับคู่" เป็นสตริงย่อยที่เป็นสมาชิกของภาษาและค่าส่งคืนคือจุดเริ่มต้นและจุดสิ้นสุดของสตริงย่อยภายในสตริงที่มีขนาดใหญ่กว่า
จุดของ lookaheads และ lookbehinds นั้นไม่มากนักที่จะแนะนำความสามารถในการจับคู่ภาษาที่ไม่ใช่ภาษาปกติ แต่ควรปรับตำแหน่งที่เครื่องยนต์รายงานจุดเริ่มต้นและจุดสิ้นสุดของสตริงย่อยที่ตรงกัน
ฉันอาศัยคำอธิบายที่http://www.regular-expressions.info/lookaround.html เอนจิ้นของ regex ที่สนับสนุนฟีเจอร์นี้ (Perl, TCL, Python, Ruby, ... ) ดูเหมือนว่าจะมีพื้นฐานมาจากการย้อนรอย (กล่าวคือมันรองรับชุดภาษาที่มีขนาดใหญ่กว่าภาษาทั่วไป) ดูเหมือนว่าพวกเขากำลังใช้งานคุณลักษณะนี้เป็นส่วนขยาย "ย้อนกลับ" ที่ค่อนข้างง่ายของการย้อนรอยแทนที่จะพยายามสร้างออโต จำกัด อันแท้จริงเพื่อดำเนินงาน
มองเชิงบวก
ไวยากรณ์สำหรับlookahead บวกคือregex(?=
)
ดังนั้นสำหรับตัวอย่างq(?=u)
ตรงq
เท่านั้นถ้ามันจะตามมาด้วยแต่ไม่ตรงกับu
u
ฉันคิดว่าพวกเขาใช้สิ่งนี้ด้วยความหลากหลายในการย้อนรอย สร้าง FSM สำหรับนิพจน์ก่อนที่จะมองเชิงบวก เมื่อการแข่งขันนั้นจำได้ว่ามันสิ้นสุดที่ไหนและเริ่ม FSM ใหม่ที่แสดงถึงการแสดงออกภายใน lookahead เชิงบวก หากการแข่งขันนั้นคุณมี "การแข่งขัน" แต่การแข่งขัน "จบ" ก่อนที่ตำแหน่งที่เริ่มการแข่งขันเชิงบวก lookahead
ส่วนเดียวของสิ่งนี้ที่จะยากโดยไม่ต้องย้อนรอยคือคุณต้องจำจุดในอินพุตที่ lookahead เริ่มต้นและย้ายเทปอินพุตของคุณกลับไปที่ตำแหน่งนี้หลังจากคุณจับคู่เสร็จแล้ว
Lookahead เชิงลบ
ไวยากรณ์สำหรับlookahead เชิงลบเป็นregex(?!
)
ดังนั้นสำหรับตัวอย่างq(?!u)
ตรงแต่ถ้ามันไม่ได้ตามมาด้วยq
u
นี่อาจเป็นได้ทั้งq
ตัวอักษรอื่นหรือq
ตามท้ายสุดของสตริง ฉันคิดว่าสิ่งนี้ถูกนำไปใช้โดยการสร้าง NFA สำหรับนิพจน์ lookahead จากนั้นทำสำเร็จก็ต่อเมื่อ NFA ไม่สามารถจับคู่สตริงที่ตามมาได้
หากคุณต้องการที่จะทำโดยไม่ต้องพึ่งพา backtracking คุณสามารถลบล้าง NFA ของนิพจน์ lookahead จากนั้นให้ปฏิบัติเช่นเดียวกับที่คุณปฏิบัติกับ lookahead เชิงบวก
มองโลกในแง่ดี
(?<=
)
(?=q)u
u
q
q
nnn
คุณอาจจะสามารถใช้สิ่งนี้ได้โดยไม่ต้องย้อนรอยโดยการตัดกันของ "สตริงที่ลงท้ายด้วยregex " กับส่วนใด ๆ ของ regex ที่มาก่อนตัวดำเนินการ lookbehind นี่จะเป็นเรื่องยุ่งยากเพราะ lookbehind regexอาจต้องมองย้อนกลับไปมากกว่าจุดเริ่มต้นปัจจุบันของอินพุต
มองโลกในแง่ลบ
ไวยากรณ์สำหรับlookbehind เชิงลบเป็นregex(?<!
)
ดังนั้นสำหรับตัวอย่างเช่น(?<!q)u
การแข่งขันแต่ถ้ามันไม่ได้นำหน้าด้วยu
q
ดังนั้นมันจะตรงกับu
ในumbrella
และu
ในdoubt
แต่ไม่ได้อยู่ในu
quick
อีกครั้งดูเหมือนว่าจะทำได้โดยการคำนวณความยาวของregexสำรองข้อมูลตัวละครหลายตัวทดสอบการจับคู่กับregexแต่ตอนนี้การแข่งขันทั้งหมดล้มเหลวหาก lookbehind ตรงกัน
คุณอาจจะสามารถใช้สิ่งนี้ได้โดยไม่ต้องย้อนรอยโดยการปฏิเสธregexจากนั้นทำเช่นเดียวกับที่คุณทำเพื่อการมองในแง่ดี