ใครช่วยอธิบายคำสองคำนี้ในวิธีที่เข้าใจได้ไหม
ใครช่วยอธิบายคำสองคำนี้ในวิธีที่เข้าใจได้ไหม
คำตอบ:
โลภจะกินมากที่สุด จากhttp://www.regular-expressions.info/repeat.html<.+>
เราเห็นตัวอย่างของการพยายามที่จะตรงกับแท็กด้วย สมมติว่าคุณมีสิ่งต่อไปนี้:
<em>Hello World</em>
คุณอาจคิดว่า<.+>
( .
หมายถึงตัวอักษรใด ๆ ที่ไม่ใช่การขึ้นบรรทัดใหม่และ+
วิธีการอย่างใดอย่างหนึ่งหรือมากกว่า ) เท่านั้นที่จะตรงกับ<em>
และ</em>
เมื่อในความเป็นจริงมันจะโลภมากและไปจากครั้งแรกไปยังหน้าล่าสุด<
>
ซึ่งหมายความว่าจะจับคู่<em>Hello World</em>
แทนที่จะเป็นสิ่งที่คุณต้องการ
การทำให้ขี้เกียจ ( <.+?>
) จะป้องกันสิ่งนี้ ด้วยการเพิ่มเครื่องหมาย?
หลัง+
เราบอกให้ทำซ้ำสองสามครั้งที่เป็นไปได้ดังนั้นสิ่งแรกที่>
เจอคือที่ที่เราต้องการหยุดการจับคู่
ฉันขอแนะนำให้คุณดาวน์โหลดRegExrซึ่งเป็นเครื่องมือที่ยอดเยี่ยมที่จะช่วยให้คุณสำรวจนิพจน์ทั่วไป - ฉันใช้มันตลอดเวลา
<[^>]+>
regex101.com/r/lW0cY6/1
'โลภ'หมายถึงการจับคู่สตริงที่ยาวที่สุดที่เป็นไปได้
'Lazy'หมายถึงจับคู่สตริงที่สั้นที่สุด
ยกตัวอย่างเช่นโลภh.+l
การแข่งขัน'hell'
ใน'hello'
แต่ขี้เกียจที่ตรงกันh.+?l
'hel'
h.+l
การแข่งขัน'helol'
ใน'helolo'
แต่ขี้เกียจที่ตรงกันh.+?l
'hel'
x?
หมายความว่าx
เป็นทางเลือก แต่+?
เป็นไวยากรณ์ที่แตกต่างกัน หมายถึงหยุดมองหาสิ่งที่ตรงกัน - จับคู่ขี้เกียจ
?
หมายถึงตัวเลือกและ+?
หมายถึงสันหลังยาว ดังนั้น\+?
หมายถึง+
เป็นตัวเลือก
+-------------------+-----------------+------------------------------+
| Greedy quantifier | Lazy quantifier | Description |
+-------------------+-----------------+------------------------------+
| * | *? | Star Quantifier: 0 or more |
| + | +? | Plus Quantifier: 1 or more |
| ? | ?? | Optional Quantifier: 0 or 1 |
| {n} | {n}? | Quantifier: exactly n |
| {n,} | {n,}? | Quantifier: n or more |
| {n,m} | {n,m}? | Quantifier: between n and m |
+-------------------+-----------------+------------------------------+
เพิ่ม ? เพื่อ quantifier เพื่อให้ ungreedy ie ขี้เกียจ
: ตัวอย่าง
สตริงทดสอบ: StackOverflow
แสดงออก reg โลภ : s.*o
เอาท์พุท: stackoverflo W
แสดงออก reg ขี้เกียจ : s.*?o
เอาท์พุท: Stacko verflow
re.match('(f)?(.*)', 'food').groups()
re.match('(f)??(.*)', 'food').groups()
ในหลัง(f)??
จะไม่ตรงกับผู้นำ 'f' แม้ว่าจะทำได้ ดังนั้น 'f' จะถูกจับคู่โดยกลุ่มการจับภาพที่สอง '. *' ฉันแน่ใจว่าคุณสามารถสร้างตัวอย่างด้วย '{n}?' เกินไป. เป็นที่ยอมรับกันว่าทั้งสองนี้ไม่ค่อยได้ใช้กันมากนัก
โลภหมายความว่าการแสดงออกของคุณจะจับคู่กับกลุ่มใหญ่ที่สุดเท่าที่จะทำได้ขี้เกียจหมายความว่าจะจับคู่กลุ่มที่เล็กที่สุดเท่าที่จะทำได้ สำหรับสตริงนี้:
abcdefghijklmc
และการแสดงออกนี้:
a.*c
abc
การแข่งขันโลภจะตรงกับสตริงทั้งหมดและการแข่งขันขี้เกียจจะตรงกับเพียงแค่ครั้งแรก
เท่าที่ฉันรู้เอนจิ้น regex ส่วนใหญ่เป็นโลภโดยค่าเริ่มต้น เพิ่มเครื่องหมายคำถามที่ส่วนท้ายของตัวนับจะเปิดใช้งานการจับคู่ที่ขี้เกียจ
ในฐานะ @Andre S ที่กล่าวถึงในความคิดเห็น
อ้างถึงตัวอย่างด้านล่างสำหรับสิ่งที่โลภและสิ่งที่ขี้เกียจ
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String args[]){
String money = "100000000999";
String greedyRegex = "100(0*)";
Pattern pattern = Pattern.compile(greedyRegex);
Matcher matcher = pattern.matcher(money);
while(matcher.find()){
System.out.println("I'm greeedy and I want " + matcher.group() + " dollars. This is the most I can get.");
}
String lazyRegex = "100(0*?)";
pattern = Pattern.compile(lazyRegex);
matcher = pattern.matcher(money);
while(matcher.find()){
System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
}
}
}
I'm greeedy and I want 100000000 dollars. This is the most I can get.
I'm too lazy to get so much money, only 100 dollars is enough for me
นำมาจากwww.regular-expressions.info
ความโลภ: ตัวนับปริมาณโลภพยายามที่จะทำซ้ำโทเค็นซ้ำหลาย ๆ ครั้งที่เป็นไปได้และค่อย ๆ ยกเลิกการแข่งขันในขณะที่เครื่องยนต์ backtracks เพื่อค้นหาการแข่งขันโดยรวม
Laziness : Lazy quantifier จะทำซ้ำโทเค็นซ้ำสองสามครั้งตามที่ต้องการและค่อย ๆ ขยายการจับคู่เป็น backtracks เครื่องยนต์ผ่าน regex เพื่อค้นหาการจับคู่โดยรวม
จากนิพจน์ทั่วไป
ปริมาณมาตรฐานในการแสดงออกปกติเป็นโลภซึ่งหมายความว่าพวกเขาจับคู่ให้มากที่สุดเท่าที่จะทำได้เพียงให้กลับมาเท่าที่จำเป็นเพื่อให้ตรงกับส่วนที่เหลือของ regex
โดยใช้ตัวบ่งชี้ที่ขี้เกียจนิพจน์จะพยายามจับคู่ที่น้อยที่สุดก่อน
การจับคู่โลภ พฤติกรรมเริ่มต้นของการแสดงออกปกติคือความโลภ นั่นหมายความว่ามันพยายามที่จะดึงข้อมูลให้ได้มากที่สุดจนกว่าจะเป็นไปตามรูปแบบแม้ว่าส่วนที่เล็กกว่านั้นจะเพียงพอในการสร้างประโยค
ตัวอย่าง:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
แทนที่จะจับคู่จนถึงเหตุการณ์แรกของ '>' มันจะดึงสตริงทั้งหมด นี่คือความโลภเริ่มต้นหรือ 'เอามันทั้งหมด' พฤติกรรมของ regex
การจับคู่ขี้เกียจในทางกลับกัน 'ใช้เวลาน้อยที่สุดเท่าที่จะเป็นไปได้' สิ่งนี้สามารถถูกทำให้มีผลโดยการเพิ่ม a ?
ท้ายของรูปแบบ
ตัวอย่าง:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
หากคุณต้องการเรียกคืนเฉพาะนัดแรกให้ใช้วิธีการค้นหาแทน
re.search('<.*?>', text).group()
#> '<body>'
ที่มา: ตัวอย่าง Python Regex
โลภหมายความว่ามันจะใช้รูปแบบของคุณจนกว่าจะไม่มีใครเหลืออยู่
Lazy จะหยุดทันทีที่พบรูปแบบแรกที่คุณขอ
ตัวอย่างทั่วไปหนึ่งที่ฉันมักพบเป็น\s*-\s*?
ของ regex([0-9]{2}\s*-\s*?[0-9]{7})
ตัวแรก\s*
จัดเป็นโลภเพราะ*
และจะมีช่องว่างสีขาวให้มากที่สุดเท่าที่จะเป็นไปได้หลังจากที่พบตัวเลขแล้วมองหาอักขระเส้นประ "-" ที่สอง\s*?
คือขี้เกียจเพราะปัจจุบัน*?
ซึ่งหมายความว่ามันจะดูอักขระช่องว่างแรกและหยุดตรงนั้น
ดีที่สุดแสดงโดยตัวอย่าง เชือก 192.168.1.1
และ regex โลภ\b.+\b
คุณอาจคิดว่าสิ่งนี้จะให้อ็อกเท็ตที่ 1 แต่ตรงกับสตริงทั้งหมด ทำไม? เนื่องจาก. + เป็นโลภและจับคู่โลภตรงกับตัวละครทุกตัวใน192.168.1.1
จนกว่าจะถึงจุดสิ้นสุดของสตริง นี่เป็นบิตที่สำคัญ! ตอนนี้มันจะเริ่มย้อนรอยทีละตัวอักษรจนกว่าจะพบการแข่งขันสำหรับโทเค็นที่ 3 ( \b
)
หากสตริงไฟล์ข้อความ 4GB และ 192.168.1.1 เป็นจุดเริ่มต้นคุณสามารถเห็นได้อย่างง่ายดายว่าการย้อนรอยนี้จะทำให้เกิดปัญหาได้อย่างไร
หากต้องการทำให้ regex non greedy (สันหลังยาว) ให้ใส่เครื่องหมายคำถามหลังจากการค้นหาโลภของคุณเช่น
*?
??
+?
สิ่งที่เกิดขึ้นตอนนี้คือโทเค็น 2 ( +?
) พบการแข่งขัน regex เคลื่อนที่ไปตามตัวละครแล้วลองใช้โทเค็นถัดไป ( \b
) แทนโทเค็น 2 ( +?
) ดังนั้นมันจึงเล็ดลอดไปด้วยขิง
หากอยู่ที่นั่นพวกเขาจะมารับ พวกเขาจะเอามันทั้งหมด:
ตัวอย่างเช่น IRS จับคู่กับ regex นี้: .*
$50,000
- กรมสรรพากรจะทำทุกอย่าง ผู้โลภ.*{4}?
ERS
ดูที่นี่สำหรับตัวอย่าง: regexr.com/4t27f
ในทางกลับกันถ้าฉันขอคืนภาษี IRS ก็กลายเป็นไม่โลภและพวกเขาใช้ตัวนับนี้:
(.{2}?)([0-9]*)
กับนิพจน์นี้: $50,000
กลุ่มแรกไม่ตรงกับความต้องการและตรงเท่านั้น$5
- ดังนั้นฉันจึงได้รับ$5
เงินคืน ส่วนที่เหลือถูกลุงแซมนำไปใช้อย่างสิ้นเปลือง
มันสำคัญถ้าคุณพยายามจับคู่บางส่วนของนิพจน์ บางครั้งคุณไม่ต้องการจับคู่ทุกอย่าง
พยายามเข้าใจพฤติกรรมดังต่อไปนี้:
var input = "0014.2";
Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"
input = " 0014.2";
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"
input = " 0014.2";
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""