ปริมาณที่โลภเทียบกับความลังเลเทียบกับความเป็นเจ้าของ


357

ฉันพบบทช่วยสอนที่ยอดเยี่ยมเกี่ยวกับการแสดงออกปกติและในขณะที่ฉันเข้าใจอย่างหยั่งรู้ในสิ่งที่ "โลภ", "ลังเล" และ "ความเป็นเจ้าของ" ตัวบ่งชี้ทำดูเหมือนว่าจะมีช่องโหว่ร้ายแรงในความเข้าใจของฉัน

โดยเฉพาะในตัวอย่างต่อไปนี้:

Enter your regex: .*foo  // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.

Enter your regex: .*?foo  // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.

Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.

คำอธิบายกล่าวถึงการกินทั้งสายป้อนข้อมูลจดหมายถูกใช้หมดการสำรองข้อมูลตัวจับคู่การเกิด "foo" ที่ถูกต้องที่สุดได้รับการสำรอกฯลฯ

แต่แม้จะมีคำอุปมาอุปมัยที่ดีที่ฉันยังไม่เข้าใจในสิ่งที่ถูกกัดกินโดยใคร ... คุณรู้ของการกวดวิชาอื่นที่อธิบาย (สังเขป) วิธีปกติการทำงานของการแสดงออกเครื่องมือ?

อีกวิธีหนึ่งถ้าใครบางคนสามารถอธิบายในประโยคที่แตกต่างกันบ้างในย่อหน้าต่อไปนี้นั่นจะเป็นการชื่นชมอย่างมาก:

ตัวอย่างแรกใช้ตัวระบุปริมาณโลภ * เพื่อค้นหา "อะไร" ศูนย์หรือมากกว่าครั้งตามด้วยตัวอักษร "f" "o" "o" เนื่องจาก quantifier เป็นโลภส่วน. * ของนิพจน์จะกินสตริงอินพุตทั้งหมดก่อน ณ จุดนี้การแสดงออกโดยรวมไม่สามารถทำได้เพราะตัวอักษรสามตัวสุดท้าย ("f" "o" "o") ได้ถูกใช้ไปแล้ว ( โดยใคร? ) ดังนั้นผู้จับคู่ช้าลง ( จากขวาไปซ้าย ) ทีละตัวอักษรหนึ่งครั้งจนกระทั่งเกิดเหตุการณ์ "foo" ที่ถูกต้องที่สุดได้รับการสำรอก ( สิ่งนี้หมายความว่าอะไร? ) ซึ่งการแข่งขันประสบความสำเร็จ

อย่างไรก็ตามตัวอย่างที่สองไม่เต็มใจดังนั้นจึงเริ่มจากการบริโภคครั้งแรก ( โดยใคร? ) "ไม่มีอะไร" เนื่องจาก "foo" ไม่ปรากฏที่จุดเริ่มต้นของสตริงจึงถูกบังคับให้กลืน ( ใครกลืน?) อักษรตัวแรก ("x") ซึ่งเรียกการจับคู่แรกที่ 0 และ 4 การทดสอบของเราดำเนินการต่อไป จนกว่าสตริงอินพุตจะหมด พบอีกนัดที่ 4 และ 13

ตัวอย่างที่สามล้มเหลวในการค้นหาคู่ที่ตรงกันเนื่องจากตัวระบุนั้นครอบครอง ในกรณีนี้สตริงการป้อนข้อมูลทั้งหมดจะถูกใช้งานโดย. * +, ( อย่างไร? ) โดยไม่เหลืออะไรเลยเพื่อตอบสนอง "foo" ที่ส่วนท้ายของนิพจน์ ใช้ quantifier ที่เป็นเจ้าของสำหรับสถานการณ์ที่คุณต้องการยึดบางสิ่งบางอย่างโดยไม่ต้องถอยกลับ (หมายถึงอะไรกลับ ) มันจะมีประสิทธิภาพสูงกว่าปริมาณโลภที่เท่ากันในกรณีที่ไม่พบการแข่งขันทันที


22
Maximalปริมาณชอบ*, +และ?มีความโลภ Minimalปริมาณชอบ*?, +?และ??มีความขี้เกียจ หวงปริมาณชอบ*+, ++และ?+มีเหนียว
tchrist

6
คำถามนี้ถูกเพิ่มไปยังคำถามที่พบบ่อยของสแต็คโอเวอร์โฟลว์นิพจน์ปกติภายใต้ "ปริมาณ> มากกว่าความแตกต่าง ... "
aliteralmind

ที่น่าสนใจ: Java ™ Tutorials - ความแตกต่างระหว่างโลภลังเลและปริมาณที่เป็นกรรมสิทธิ์ - เลื่อนลงเพื่อดูส่วน
Guy Coder

คำตอบ:


495

ฉันจะให้มันยิง

ความโลภปริมาณการแข่งขันครั้งแรกมากที่สุดเท่าที่เป็นไปได้ ดังนั้นการ.*จับคู่สตริงทั้งหมด จากนั้นผู้จับคู่พยายามจับคู่fต่อไปนี้ แต่ไม่มีอักขระเหลืออยู่ ดังนั้นมันจึงเป็น "backtracks" ทำให้การหาปริมาณโลภจับคู่หนึ่งตัวอักษรน้อยลง (ทิ้ง "o" ไว้ที่ส่วนท้ายของสตริงที่ไม่ตรงกัน) นั่นยังไม่ตรงกับfใน regex ดังนั้นมันจะย้อนกลับไปอีกหนึ่งขั้นตอนทำให้การหาปริมาณโลภจับคู่ตัวละครน้อยลงอีกหนึ่งตัว (ปล่อย "oo" ไว้ที่ส่วนท้ายของสตริง) ที่ยังคงไม่ตรงกับfใน regex จึง backtracks หนึ่งในขั้นตอนมากขึ้น (ออกจาก "foo" ในตอนท้ายของสตริงตรงกัน) ตอนนี้ผู้จับคู่ได้ตรงกับfใน regexooมีการจับคู่เกินไป ที่ประสบความสำเร็จ!

ลังเลหรือ "ไม่โลภ" ปริมาณการแข่งขันครั้งแรกน้อยที่สุด ดังนั้น.*จับคู่ไม่มีอะไรในตอนแรกปล่อยให้ทั้งสตริงที่ไม่ตรงกัน จากนั้นผู้จับคู่พยายามจับคู่fต่อไปนี้ แต่ส่วนที่ไม่ตรงกันของสตริงเริ่มต้นด้วย "x" ดังนั้นจึงไม่ทำงาน backer ของ matcher ทำให้การหาปริมาณที่ไม่ใช่โลภตรงกับตัวละครอีกหนึ่งตัว (ตอนนี้มันตรงกับ "x" โดยปล่อย "fooxxxxxxfoo" ที่ไม่ตรงกัน) จากนั้นจะพยายามจับคู่fซึ่งประสบความสำเร็จและoและต่อไปoในการแข่งขัน regex เกินไป ที่ประสบความสำเร็จ!

ในตัวอย่างของคุณจากนั้นจะเริ่มกระบวนการใหม่โดยใช้ส่วนที่ไม่ตรงกันของสตริง "xxxxxxfoo" ที่ทำตามกระบวนการเดียวกัน

หวงปริมาณเป็นเช่นเดียวกับปริมาณโลภ แต่ไม่ได้เปลี่ยนใจ ดังนั้นมันจึงเริ่มต้นด้วยการ.*จับคู่สตริงทั้งหมดโดยไม่มีสิ่งใดเทียบได้ จากนั้นก็ไม่มีอะไรเหลือไว้ให้จับคู่กับfใน regex เนื่องจากตัวบ่งชี้ความเป็นเจ้าของไม่ย้อนรอยการแข่งขันจึงล้มเหลว


15
+1 คำตอบที่ดี ฉันจะเพิ่มเท่านั้น: ไปอ่านMastering Regular Expressions (ฉบับที่ 3)
ridgerunner

@Anomie สายไปหน่อย แต่ในส่วนที่เป็นเจ้าของฉันคิดว่าคุณหมายถึงมันเริ่มต้นด้วย .*+ (สังเกต "+")
RD

3
Quantifier ความเป็นเจ้าของทำอะไรกันแน่? ถ้ามันไม่ตรงกับนี้ (ฉันหมายถึงว่ามันคืออะไรถ้าคุณไม่สามารถมีตัวละครได้หลังจากนั้น)
relipse

4
@relipse: คุณจะใช้มันในสถานการณ์ที่คุณรู้ว่าการย้อนรอยจะไม่ช่วยได้ แต่อาจจะไม่ใช่.*+สิ่งที่ตรงกับทุกอย่าง ตัวอย่างเช่นหากคุณมีรูปแบบ[xyz]*fooไม่มีวิธีใดที่การย้อนรอยของ x, y's และ z ที่จับคู่โดย[xyz]*บิตจะทำให้fooบิตต่อไปนี้ตรงกันดังนั้นคุณจึงสามารถเร่งความเร็วได้โดยทำให้เป็นกรรมสิทธิ์
Anomie

4
@moodboom มีศูนย์ที่ไม่เคยมีมาก่อน (ความจริงทางคณิตศาสตร์) ที่ปริมาณการครอบครองจะสร้างการจับคู่ที่จะไม่ถูกสร้างขึ้นโดยปริมาณโลภที่เรียบง่าย มีบางครั้งที่พวกเขาจะสร้างการแข่งขันไม่ได้เมื่อปริมาณโลภจะสร้างการแข่งขัน สำหรับกรณีอื่น ๆ ทั้งหมด (ในกรณีที่ความโลภและความเป็นเจ้าของให้ผลลัพธ์เหมือนกัน) ตัวตรวจจับปริมาณความลับจะให้ประสิทธิภาพที่เพิ่ม
Wildcard ใน

49

มันเป็นเพียงแค่การส่งออกการปฏิบัติของฉันที่จะเห็นภาพฉาก -

ภาพภาพ


3
ยกเว้นว่าฉันคิดว่ากรณีสุดท้ายเป็นเจ้าของไม่ควรมี n ผ่าน - เพียงแค่คว้าสตริงทั้งหมดในครั้งเดียว
รักษา mods ของคุณดี

@phyzome ฉันคิดว่ามันโอเคตอนนี้เหรอ?
SIslam

1
ขอบคุณสำหรับคำอธิบายภาพ :)
ลาร์ส Moelleken

ในEXPRESSION .*?foo() [f] [o] [o]สี่เหลี่ยมมุมฉากควรเป็นสีเหลือง5th passหรือไม่
tonix

1
@tonix ใช่! สีเหลืองที่ต้องทำเพื่อเป็นส่วนหนึ่งในการจับคู่การแสดงออกและ.*?foo .*+foo
SIslam

24

ฉันไม่เคยได้ยินคำว่า 'สำรอก' หรือ 'ถอยออก' ที่แน่นอนมาก่อน วลีที่จะแทนที่สิ่งเหล่านี้คือ "backtracking" แต่ 'สำรอก' ดูเหมือนว่าเป็นวลีที่ดีสำหรับ "เนื้อหาที่ได้รับการยอมรับอย่างไม่แน่นอนก่อนที่จะ backtracking โยนมันออกไปอีกครั้ง"

สิ่งสำคัญที่ต้องรู้เกี่ยวกับเอ็นจิ้น regex ส่วนใหญ่ก็คือพวกเขากำลังย้อนรอย : พวกเขาจะยอมรับการจับคู่ที่มีศักยภาพและไม่แน่นอนในขณะที่พยายามจับคู่เนื้อหาทั้งหมดของ regex หาก regex ไม่สามารถจับคู่ได้อย่างสมบูรณ์ในครั้งแรกจากนั้นเครื่องยนต์ regex จะย้อนกลับในหนึ่งในการแข่งขัน มันจะพยายามจับคู่*, +, ?, สับเปลี่ยนหรือ{n,m}การทำซ้ำที่แตกต่างกันและลองอีกครั้ง (และใช่กระบวนการนี้อาจใช้เวลานาน)

ตัวอย่างแรกใช้ตัวระบุปริมาณโลภ * เพื่อค้นหา "อะไร" ศูนย์หรือมากกว่าครั้งตามด้วยตัวอักษร "f" "o" "o" เนื่องจาก quantifier เป็นโลภส่วน. * ของนิพจน์จะกินสตริงอินพุตทั้งหมดก่อน ณ จุดนี้การแสดงออกโดยรวมไม่สามารถทำได้เพราะตัวอักษรสามตัวสุดท้าย ("f" "o" "o") ได้ถูกใช้ไปแล้ว ( โดยใคร? )

ล่าสุดสามตัวอักษรf, oและoถูกบริโภคแล้วโดยเริ่มต้น.*เป็นส่วนหนึ่งของกฎ อย่างไรก็ตามองค์ประกอบถัดไปใน regex fไม่มีอะไรเหลืออยู่ในสตริงอินพุต เครื่องยนต์จะถูกบังคับให้ย้อนกลับในการ.*แข่งขันครั้งแรกและลองจับคู่ตัวละครทั้งหมด แต่สุดท้าย (มันอาจจะฉลาดและย้อนกลับไปที่ทั้งหมด แต่สุดท้าย - สาม - เพราะมีสามคำที่แท้จริง แต่ฉันไม่ทราบรายละเอียดการใช้งานในระดับนี้)

ดังนั้นผู้จับคู่จึงค่อย ๆ ถอยออก ( จากขวาไปซ้าย? ) จดหมายฉบับหนึ่งทีละครั้งจนกว่าการเกิด "foo" ที่ถูกต้องที่สุดได้รับการสำรอก ( สิ่งนี้หมายความว่าอย่างไร ) ซึ่ง

ซึ่งหมายความว่าfooได้แน่นอน.*รับรวมทั้งเมื่อมีการจับคู่ เพราะความพยายามที่ล้มเหลวที่พยายามเครื่องยนต์ regex .*ยอมรับตัวละครตัวหนึ่งในน้อยลง หากมีการแข่งขันที่ประสบความสำเร็จก่อนที่จะ.*ในตัวอย่างนี้แล้วเครื่องยนต์อาจจะพยายามตัดทอน.*การแข่งขัน (จากขวาไปซ้ายตามที่คุณชี้ให้เห็นเพราะมันเป็นรอบคัดเลือกโลภ) และถ้ามันไม่สามารถที่จะแข่งขัน ปัจจัยการผลิตทั้งหมดแล้วมันอาจจะถูกบังคับให้ต้องประเมินอีกครั้งว่าสิ่งที่มันได้จับคู่ก่อน.*ในตัวอย่างสมมุติของฉัน

ชี้ให้เห็นว่าการแข่งขันประสบความสำเร็จและการค้นหาจะสิ้นสุดลง

อย่างไรก็ตามตัวอย่างที่สองไม่เต็มใจดังนั้นมันจึงเริ่มต้นด้วยการบริโภคครั้งแรก ( โดยใคร? ) "ไม่มีอะไร" เพราะ "foo"

ไม่มีการใช้งานเริ่มต้นโดย.?*จะใช้จำนวนที่สั้นที่สุดเท่าที่เป็นไปได้ของสิ่งที่อนุญาตให้ส่วนที่เหลือของ regex จับคู่

ไม่ปรากฏที่จุดเริ่มต้นของสตริงมันถูกบังคับให้กลืน ( ใครกลืน?)

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

อักษรตัวแรก ("x") ซึ่งเป็นต้นเหตุของการจับคู่แรกที่ 0 และ 4 ชุดทดสอบของเราจะดำเนินการต่อไปจนกว่าสตริงอินพุตจะหมด พบอีกนัดที่ 4 และ 13

ตัวอย่างที่สามล้มเหลวในการค้นหาคู่ที่ตรงกันเนื่องจากตัวระบุนั้นครอบครอง ในกรณีนี้สตริงการป้อนข้อมูลทั้งหมดจะถูกใช้โดย * +, ( อย่างไร? )

.*+จะใช้มากที่สุดเท่าที่เป็นไปได้และจะไม่เปลี่ยนใจไปหาแมตช์ใหม่เมื่อ regex เป็นทั้งล้มเหลวในการหาคู่ เพราะรูปแบบที่เจ้าของไม่ได้ดำเนินการย้อนรอยคุณอาจจะไม่เห็นการใช้งานจำนวนมากที่มี.*+แต่กับชั้นเรียนตัวอักษรหรือข้อ จำกัด account: [[:digit:]]*+ phone: [[:digit:]]*+ที่คล้ายกัน:

สิ่งนี้สามารถเร่งความเร็วการจับคู่ regex ได้อย่างมากเนื่องจากคุณกำลังบอกเอ็นจิ้น regex ว่าไม่ควรย้อนกลับไปที่การจับคู่ที่เป็นไปได้ถ้าอินพุตไม่ตรงกัน (หากคุณต้องเขียนรหัสที่ตรงกันทั้งหมดด้วยมือสิ่งนี้จะคล้ายกับที่ไม่เคยใช้putc(3)เพื่อ 'ผลักดัน' อักขระป้อนข้อมูลมันจะคล้ายกับรหัสที่ไร้เดียงสาอย่างใดอย่างหนึ่งที่อาจเขียนในครั้งแรกยกเว้นเอ็นจิ้น regex วิธีที่ดีกว่าตัวละครเดียวของ push-back พวกเขาสามารถย้อนกลับไปที่ศูนย์และลองอีกครั้ง :)

นอกจากความเร็วที่อาจเกิดขึ้นแล้วสิ่งนี้ยังช่วยให้คุณสามารถเขียน regex ที่ตรงกับสิ่งที่คุณต้องการจับคู่ ฉันมีปัญหาในการหาตัวอย่างง่าย ๆ :) แต่การเขียน regex โดยใช้ปริมาณที่มากเกินไปและความโลภสามารถทำให้คุณได้แมทช์ที่แตกต่างกันและอีกอันหนึ่งอาจเหมาะสมกว่า

ปล่อยให้ไม่มีอะไรเหลือเพื่อตอบสนอง "foo" ในตอนท้ายของนิพจน์ ใช้ quantifier ที่เป็นเจ้าของสำหรับสถานการณ์ที่คุณต้องการยึดบางสิ่งบางอย่างโดยไม่ต้องถอยกลับ (หมายถึงอะไรกลับ ) มันจะมีประสิทธิภาพสูงกว่า

"Backing off" ในบริบทนี้หมายถึง "backtracking" - ทิ้งการแข่งขันบางส่วนชั่วคราวเพื่อลองการแข่งขันบางส่วนอีกครั้งซึ่งอาจหรืออาจไม่สำเร็จ

ปริมาณโลภที่เท่ากันในกรณีที่ไม่พบการแข่งขันทันที


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

2
ยืนยัน: "นั่นคือสิ่งที่การจัดกลุ่มอะตอมและปริมาณที่เป็นกรรมสิทธิ์สำหรับ: ประสิทธิภาพโดยไม่อนุญาตให้ย้อนรอย" จาก regular-expressions.info ดังนั้นคำสั่งในคำตอบนี้"แต่มากกว่าความเร็วที่อาจเกิดขึ้นสิ่งนี้สามารถให้คุณเขียน regex ที่ตรงกับสิ่งที่คุณต้องการจับคู่ได้" จริง ๆ แล้วค่อนข้างไม่ถูกต้อง
สัญลักษณ์แทน

1
@ Wildcard ขอบคุณสำหรับความคิดเห็น นั่นอาจอธิบายได้ว่าทำไมฉันถึงมีปัญหาในการหาตัวอย่าง ฮิฮิ.
sarnold

19

http://swtch.com/~rsc/regexp/regexp1.html

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

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

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

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

  • ปริมาณโลภบอกเครื่องยนต์ให้เริ่มต้นด้วยสตริงทั้งหมด (หรืออย่างน้อยก็ทั้งหมดที่ไม่ได้จับคู่โดยส่วนก่อนหน้าของการแสดงออกปกติ) และตรวจสอบว่ามันตรงกับ regexp ถ้าเป็นเช่นนั้นยอดเยี่ยม; เครื่องยนต์สามารถดำเนินการต่อด้วยส่วนที่เหลือของ regexp หากไม่ใช่จะลองอีกครั้ง แต่ตัดส่วนอักขระหนึ่งตัว (ตัวสุดท้าย) ออกจากส่วนของสตริงที่ต้องการตรวจสอบ หากไม่ได้ผลก็จะตัดตัวละครอื่นออกไปดังนั้นปริมาณโลภจะตรวจสอบการจับคู่ที่เป็นไปได้ตามลำดับจากยาวที่สุดไปจนถึงสั้นที่สุด

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

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

นี่คือเหตุผลที่การจับคู่ตัวบ่งชี้ความล้มเหลวล้มเหลวในตัวอย่างของคุณ: การ.*+ตรวจสอบกับสตริงทั้งหมดซึ่งมันตรงกัน แต่จากนั้นเครื่องยนต์จะค้นหาอักขระเพิ่มเติมfooหลังจากนั้น - แต่แน่นอนว่ามันไม่พบพวกเขาเพราะคุณ อยู่ที่ท้ายสตริงแล้ว ถ้ามันเป็นตัวบอกปริมาณโลภมันจะย้อนรอยและลอง.*จับคู่กับตัวละครถัดไปสุดท้ายเท่านั้นจากนั้นก็ขึ้นไปที่ตัวละครที่สามถึงตัวสุดท้ายจากนั้นก็ขึ้นไปที่ตัวละครที่สี่ถึงตัวสุดท้าย มีfooซ้ายหลังจากที่.*"กิน" ส่วนก่อนหน้าของสตริง


1
นั่นเป็นแหล่งที่ยอดเยี่ยม ฉันรักแผนภาพเครื่องของรัฐ :)
Regex Rookie

@Regex Rookie: ดีใจที่คุณชอบ :) หลังจากมองไปที่ไซต์นั้นแล้วฉันคิดว่าฉันควรจะอธิบายให้ชัดเจนว่าจุดประสงค์ของมันคือเพื่อส่งเสริมการใช้งานทางเลือกของเอ็นจิ้นนิพจน์ทั่วไป อัลกอรึทึมการย้อนรอย I (บางส่วน) และคำตอบอื่น ๆ อธิบายเป็นวิธีที่ช้า มันเป็นอัลกอริทึมที่แยกต่างหากจากแนวคิด NFA / DFA ที่อธิบายไว้ในหน้าเว็บ Backtracking นั้นง่ายต่อการเข้าใจซึ่งเป็นสาเหตุที่ทำให้ regexps อธิบายโดยทั่วไปสำหรับผู้เริ่มต้น
David Z

@ David Zaslavsky: คำอธิบายที่ดี ความคิดเห็นของคุณในวงเล็บใน "ตัวบอกปริมาณโลภบอกให้เครื่องยนต์เริ่มต้นด้วยสตริงทั้งหมด (หรืออย่างน้อยนั่นคือทั้งหมดที่ไม่ได้จับคู่กับส่วนก่อนหน้าของนิพจน์ทั่วไป)" พวกเขายังใช้กับปริมาณที่ไม่เต็มใจและเป็นเจ้าของ สิ่งนี้ทำให้คำอธิบายของคุณเข้ากันได้กับสิ่งที่เกิดขึ้นเมื่อเราเปลี่ยนรูปแบบตัวอย่างจาก (". * foo"; ". *? foo"; และ ". * + foo") เป็น ("foo. *"; "foo. *? "; และ" foo. * + ")
John Bentley

ที่จริงแล้ว xfooxxxxxxfoo ไม่ตรงกัน * foo ในแบบปกติ (ความหมายด้านวิทยาศาสตร์คอมพิวเตอร์) ของการแสดงออกปกติ NFA จะเป็นรัฐที่มันวนรอบตัวเองด้วยอักขระใด ๆ และจากนั้นก็สามารถข้ามไป foo DFA จะเป็นคำแปลที่ตรงไปตรงมาของ NFA นั้น สามารถทำได้ใน 8 รัฐ
user4951

@JimThio ใช่เพราะนั่นไม่ใช่ปริมาณที่เป็นเจ้าของ
David Z

12

นี่คือสิ่งที่ฉันใช้โดยใช้ตำแหน่งของเซลล์และดัชนี (ดูแผนภาพที่นี่เพื่อแยกความแตกต่างของเซลล์ออกจากดัชนี)

โลภ - จับคู่ให้มากที่สุดเท่าที่จะทำได้เพื่อหาปริมาณโลภและ regex ทั้งหมด หากไม่มีการแข่งขันให้ย้อนกลับไปที่ตัวนับโลภ

สตริงอินพุต: xfooxxxxxxfoo
Regex: * foo

Regexด้านบนมีสองส่วน:
(i) '. *' และ
(ii) 'foo'

แต่ละขั้นตอนด้านล่างจะวิเคราะห์สองส่วน คำอธิบายเพิ่มเติมเกี่ยวกับการจับคู่กับ 'ผ่าน' หรือ 'ล้มเหลว' อยู่ในวงเล็บปีกกา

ขั้นตอนที่ 1:
(i). * = xfooxxxxxxfoo - PASS ('. *' เป็นตัวนับโลภและจะใช้ Input String ทั้งหมด)
(ii) foo = ไม่มีอักขระเหลือให้จับคู่หลังจากดัชนี 13 - FAIL
Match ล้มเหลว

ขั้นตอนที่ 2:
(i). * = xfooxxxxxxfo - PASS (Backtracking บนตัวบอกปริมาณ '' * ')
(ii) foo = o - FAIL
Match ล้มเหลว

ขั้นตอนที่ 3:
(i). * = xfooxxxxxxf - PASS (Backtracking บนตัวบอกปริมาณโลภ '.' ')
(ii) foo = oo - FAIL
Match ล้มเหลว

ขั้นตอนที่ 4:
(i). * = xfooxxxxxx - PASS (Backtracking บนตัวบอกปริมาณโลภ '.')
(ii) foo = foo - PASS
Report MATCH

ผลลัพธ์: 1 การแข่งขัน
ฉันพบข้อความ "xfooxxxxxxfoo" เริ่มต้นที่ดัชนี 0 และสิ้นสุดที่ดัชนี 13

Reluctant - จับคู่ให้น้อยที่สุดเท่าที่จะทำได้เพื่อให้ได้ปริมาณที่ไม่เต็มใจและจับคู่ regex ทั้งหมด หากไม่มีการจับคู่ให้เพิ่มตัวอักษรไปยังตัวบอกปริมาณที่ไม่เต็มใจ

สตริงอินพุต: xfooxxxxxxfoo
Regex :. *? foo

Regex ด้านบนมีสองส่วน:
(i) '. *?' และ
(ii) 'foo'

ขั้นตอนที่ 1
:. *? = '' (ว่าง) - PASS (จับคู่น้อยที่สุดเท่าที่จะทำได้เพื่อให้ได้ปริมาณที่ไม่เต็มใจ '. *?' ดัชนี 0 ที่มี '' คือคู่ที่ตรงกัน)
foo = xfo - FAIL (เซลล์ 0,1,2 - เช่นดัชนีระหว่าง 0 และ 3)
แข่งขันล้มเหลว

ขั้นตอนที่ 2
:. *? = x - PASS (เพิ่มตัวละครไปยังตัวบอกปริมาณลังเล '. *?'. เซลล์ 0 ที่มี 'x' คือคู่ที่ตรงกัน)
foo = foo - PASS
Report MATCH

ขั้นตอนที่ 3
:. *? = '' (ว่าง) - PASS (จับคู่ให้น้อยที่สุดเท่าที่จะทำได้เพื่อให้ได้ปริมาณที่ไม่เต็มใจ '. *?' ดัชนี 4 ที่มี '' เป็นการแข่งขัน)
foo = xxx - FAIL (เซลล์ 4,5,6 - ดัชนีเช่นระหว่าง 4 และ 7)
แข่งขันล้มเหลว

ขั้นตอนที่ 4
:. *? = x - PASS (เพิ่มตัวอักษรไปยังตัวบอกปริมาณลังเล '. *?'. เซลล์ 4)
foo = xxx - FAIL (เซลล์ 5,6,7 - ดัชนีเช่นระหว่าง 5 และ 8)
จับคู่ล้มเหลว

ขั้นตอนที่ 5
:. *? = xx - PASS (เพิ่มอักขระลงในจำนวนที่ไม่เต็มใจ '. *?' เซลล์ 4 ถึง 5. )
foo = xxx - FAIL (เซลล์ 6,7,8 - ดัชนีเช่นระหว่าง 6 และ 9)
จับคู่ล้มเหลว

ขั้นตอนที่ 6:.
*? = xxx - PASS (เพิ่มอักขระลงในจำนวนที่ไม่เต็มใจ '. *?'. เซลล์ 4 ถึง 6. )
foo = xxx - FAIL (เซลล์ 7,8,9 - ดัชนีเช่นระหว่าง 7 และ 10)
จับคู่ล้มเหลว

ขั้นตอนที่ 7:.
*? = xxxx - PASS (เพิ่มอักขระลงในจำนวนที่ไม่เต็มใจ '. *?'. เซลล์ 4 ถึง 7. )
foo = xxf - FAIL (เซลล์ 8,9,10 - ดัชนีเช่นระหว่าง 8 และ 11)
จับคู่ล้มเหลว

ขั้นตอนที่ 8:.
*? = xxxxx - PASS (เพิ่มตัวละครไปยังตัวบอกปริมาณลังเล '. *?'. เซลล์ 4 ถึง 8)
foo = xfo - FAIL (เซลล์ 9,10,11 - ดัชนีเช่นระหว่าง 9 และ 12)
จับคู่ล้มเหลว

ขั้นตอนที่ 9:.
*? = xxxxxx - PASS (เพิ่มอักขระลงในปริมาณที่ไม่เต็มใจ '. *?'. เซลล์ 4 ถึง 9)
foo = foo - PASS (เซลล์ 10,11,12 - ดัชนีเช่นระหว่าง 10 และ 13)
รายงานการจับคู่

ขั้นตอนที่ 10:.
*? = '' (ว่าง) - PASS (จับคู่น้อยที่สุดเท่าที่จะทำได้เพื่อให้ได้ปริมาณที่ไม่เต็มใจ '. *?' ดัชนี 13 ว่างเปล่า)
foo = ไม่มีอักขระเหลือให้จับคู่ - FAIL (ไม่มีอะไรหลังจากดัชนี 13 ให้ตรงกัน)
การแข่งขัน ล้มเหลว

ผลลัพธ์: 2 การจับคู่
ฉันพบข้อความ "xfoo" เริ่มต้นที่ดัชนี 0 และสิ้นสุดที่ดัชนี 4
ฉันพบข้อความ "xxxxxxfoo" เริ่มต้นที่ดัชนี 4 และสิ้นสุดที่ดัชนี 13

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

สตริงอินพุต: xfooxxxxxxfoo
Regex: * + foo

Regex ด้านบนมีสองส่วน: '. * +' และ 'foo'

ขั้นตอนที่ 1
:. * + = xfooxxxxxxfoo - PASS (จับคู่ให้ได้ปริมาณมากที่สุดเท่าที่จะเป็นไปได้ '. *')
foo = ไม่มีอักขระเหลือให้จับคู่ - FAIL (ไม่มีอะไรที่จะจับคู่หลังจากดัชนี 13) การ
แข่งขันล้มเหลว

หมายเหตุ:ไม่อนุญาตให้ใช้การย้อนรอย

ผลลัพธ์: 0 การจับคู่ (es)


1

โลภ: "จับคู่ลำดับตัวละครที่ยาวที่สุดเท่าที่จะทำได้"

ลังเล: "จับคู่ลำดับอักขระที่สั้นที่สุด"

มีความเป็นไปได้: นี่เป็นเรื่องแปลกที่มันไม่ได้ (ตรงกันข้ามกับความโลภและลังเล) พยายามที่จะหาคู่ที่เหมาะสมสำหรับ regex ทั้งหมด

โดยวิธีการ: ไม่มีการใช้ตัวจับคู่รูปแบบ regex จะใช้ backtracking เครื่องมือจับคู่รูปแบบชีวิตจริงทั้งหมดนั้นเร็วมาก - เกือบจะเป็นอิสระจากความซับซ้อนของการแสดงออกปกติ!


เท่าที่ฉันรู้ว่าการใช้งานทั่วไปส่วนใหญ่ตอนนี้เต็มไปด้วยคุณสมบัติมากมายมันเป็นไปไม่ได้ที่จะไม่ใช้การย้อนรอย ดังนั้นในทางทฤษฎีแล้วพวกเขาควรจะช้ามาก ๆ ในบางกรณี แต่สำหรับกรณีส่วนใหญ่มีการเพิ่มประสิทธิภาพพิเศษที่สร้างไว้ในตัวจับคู่รูปแบบ
Robert

0

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

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

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

ปริมาณที่ไม่เต็มใจนั้นส่วนใหญ่จะเหมือนกับคุณสมบัติการโลภยกเว้นการไหลของตัวละครนั้นตรงกันข้าม - นั่นคือพวกมันเริ่มในการกักกันและไหลลงสู่ลำดับที่แอคทีฟ พฤติกรรมที่เกิดขึ้นคือลำดับต้นฉบับน้อยที่สุดจะรวมอยู่ในการแข่งขันให้ได้มากที่สุด

ปริมาณที่เป็นกรรมสิทธิ์ไม่มีการกักกันและรวมทุกอย่างไว้ในที่แน่นอนลำดับการใช้งาน

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