JavaRush /จาวาบล็อก /Random-TH /RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่...
Artur
ระดับ
Tallinn

RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 2

เผยแพร่ในกลุ่ม
RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 1 ต้นฉบับที่นี่ ในส่วนสุดท้าย เราเชี่ยวชาญนิพจน์ทั่วไปที่ง่ายที่สุด และได้เรียนรู้บางอย่างไปแล้ว ในส่วนนี้เราจะศึกษาการออกแบบที่ซับซ้อนมากขึ้นเล็กน้อย แต่เชื่อฉันเถอะว่ามันจะไม่ยากอย่างที่คิด RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ส่วนที่ 2 - 1เอาล่ะมาทำต่อ!

ขั้นตอนที่ 8: เครื่องหมายดาว*และเครื่องหมายบวก+

RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ส่วนที่ 2 - 2จนถึงตอนนี้ เราสามารถจับคู่สตริงที่มีความยาวที่กำหนดได้มากหรือน้อยเท่านั้น แต่ในปัญหาล่าสุด เราได้เข้าใกล้ขีดจำกัดของสิ่งที่เราสามารถทำได้ด้วยสัญลักษณ์ที่เราเคยเห็นมา ตัวอย่างเช่น สมมติว่าเราไม่ได้จำกัดอยู่เพียงตัวระบุ Java 3 อักขระ แต่เราสามารถมีตัวระบุที่มีความยาวเท่าใดก็ได้ โซลูชันที่อาจได้ผลในตัวอย่างก่อนหน้านี้จะไม่ทำงานในตัวอย่างต่อไปนี้:
รูปแบบ: [a-zA-Z_$]\w\w 
สตริง:   __e $12 3 3.2 สำหรับบาร์ r a23 mm ab x
ตรงกัน: ^^^ ^^^ ^^^ ^^^  
( ตัวอย่าง ) บันทึกว่าเมื่อตัวระบุถูกต้องแต่ยาวเกิน 3 ตัวอักษร ระบบจะจับคู่เฉพาะอักขระสามตัวแรกเท่านั้น และเมื่อตัวระบุถูกต้อง แต่มีอักขระน้อยกว่า 3 ตัว regex จะไม่พบเลย! ปัญหาคือนิพจน์ในวงเล็บ[]ตรงกับอักขระเพียงตัวเดียว เช่นเดียวกับคลาสอักขระ เช่น\w. ซึ่งหมายความว่าการจับคู่ใดๆ ในนิพจน์ทั่วไปข้างต้นจะต้องมีความยาวสามอักขระพอดี มันเลยไม่ได้ผลดีอย่างที่เราหวังไว้ *อักขระพิเศษ และสามารถช่วยได้ที่+นี่ สิ่งเหล่านี้คือตัวปรับแต่งที่สามารถเพิ่มทางด้านขวาของนิพจน์ใดๆ เพื่อให้ตรงกับนิพจน์นั้นได้มากกว่าหนึ่งครั้ง ดาว Kleene (หรือ "เครื่องหมายดอกจัน") *จะระบุว่าโทเค็นก่อนหน้าจะต้องจับคู่จำนวนครั้งเท่าใดก็ได้ รวมถึงศูนย์ครั้งด้วย เครื่องหมายบวก+จะระบุว่าคุณต้องค้นหาอย่างน้อยหนึ่งครั้ง ดังนั้น นิพจน์ที่นำหน้าถือ+เป็นข้อบังคับ (อย่างน้อยหนึ่งครั้ง) ในขณะที่นิพจน์ที่นำหน้า*เป็นทางเลือก แต่เมื่อปรากฏขึ้น ก็สามารถปรากฏกี่ครั้งก็ได้ ตอนนี้ ด้วยความรู้นี้ เราสามารถแก้ไขนิพจน์ทั่วไปข้างต้นได้:
รูปแบบ: [a-zA-Z_$]\w* 
สตริง:   __e $123 3.2 สำหรับ Barr a23mm ab x 
ตรงกัน: ^^^ ^^^^ ^^ ^^^^ ^^^^^ ^^ ^ 
( ตัวอย่าง ) ตอนนี้เราจับคู่ตัวระบุที่ถูกต้องทุกความยาวแล้ว! บิงโก! แต่จะเกิดอะไรขึ้นถ้าเราใช้ ? +แทน*?
รูปแบบ: [a-zA-Z_$]\w+ 
สตริง:   __e $123 3.2 สำหรับ Barr a23mm ab x
ตรงกัน: ^^^ ^^^^ ^^ ^^^^ ^^^^^ ^^ 
( ตัวอย่างх ) เราพลาดนัดที่แล้ว เนื่องจากต้องมี+อักขระอย่างน้อยหนึ่งตัวจึงจะตรงกันได้ แต่เนื่องจากนิพจน์ในวงเล็บ[]ที่อยู่ข้างหน้า\w+ได้ 'กิน' อักขระนั้นแล้วxจึงไม่มีอักขระเหลืออยู่อีกต่อไป การจับคู่จึงล้มเหลว เมื่อไหร่ที่เราสามารถใช้ได้+? เมื่อเราต้องค้นหารายการที่ตรงกันอย่างน้อยหนึ่งรายการ แต่ไม่สำคัญว่านิพจน์ที่กำหนดจะต้องตรงกันกี่ครั้ง เช่น ถ้าเราต้องการหาตัวเลขที่มีจุดทศนิยม ให้ทำดังนี้
รูปแบบ: \d*\.\d+ 
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 
ตรงกัน: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^  
( ตัวอย่าง ) บันทึกโดยการใส่ตัวเลขทางด้านซ้ายของจุดทศนิยมลงไป เราก็สามารถหาทั้ง 0.011 และ .2 ได้ ในการดำเนินการนี้ เราจำเป็นต้องจับคู่จุดทศนิยมหนึ่งจุดให้ตรงกันกับ\.และอย่างน้อยหนึ่งหลักทางด้านขวาของจุดทศนิยม\d+ด้วย นิพจน์ทั่วไปข้างต้นจะไม่ตรงกับตัวเลขเช่น3.เนื่องจากเราต้องการอย่างน้อยหนึ่งหลักทางด้านขวาของจุดทศนิยมจึงจะตรงกัน

ตามปกติ เราจะมาแก้ไขปัญหาง่ายๆ สองสามข้อ:

ค้นหาคำภาษาอังกฤษทั้งหมดได้จากข้อความด้านล่างนี้
ลวดลาย:
สตริง: 3 บวก 3 เป็นหก แต่ 4 บวกสามเป็น 7
ตรงกัน:    ^^^^ ^^ ^^^ ^^^ ^^^^ ^^^^^ ^^ 
( วิธีแก้ไข ) ค้นหาสัญลักษณ์ขนาดไฟล์ทั้งหมดในรายการด้านล่าง ขนาดไฟล์จะประกอบด้วยตัวเลข (มีหรือ ไม่มี จุดทศนิยม) ตามด้วยKB, MBหรือGB:TB
ลวดลาย:
สตริง:   11TB 13 14.4MB 22HB 9.9GB TB 0KB 
ตรงกัน: ^^^^ ^^^^^^ ^^^^^ ^^^  
( สารละลาย )

ขั้นตอนที่ 9: เครื่องหมายคำถาม "ไม่บังคับ"?

RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ส่วนที่ 2 - 3คุณได้เขียน regex เพื่อแก้ไขปัญหาล่าสุดแล้วหรือยัง? มันได้ผลเหรอ? ตอนนี้ลองใช้มันที่นี่:
ลวดลาย:
สตริง: 1..3KB 5...GB ..6TB
การแข่งขัน:  
แน่นอนว่า การกำหนดเหล่านี้ไม่ใช่ขนาดไฟล์ที่ถูกต้อง ดังนั้นนิพจน์ทั่วไปที่ดีไม่ควรตรงกับขนาดไฟล์อย่างใดอย่างหนึ่ง วิธีแก้ปัญหาที่ฉันเขียนเพื่อแก้ไขปัญหาสุดท้ายนั้นตรงกับทั้งหมด อย่างน้อยก็ในบางส่วน:
รูปแบบ: \d+\.*\d*[KMGT]B 
สตริง:   1..3KB  5...GB .. 6TB 
ตรงกัน: ^^^^^^ ^^^^^^ ^^^ 
( ตัวอย่าง ) แล้วปัญหาคืออะไร? ที่จริงแล้ว เราต้องหาจุดทศนิยมเพียงจุดเดียวหากมี แต่*อนุญาตให้มีการแข่งขันจำนวนเท่าใดก็ได้ รวมถึงศูนย์ด้วย มีวิธีจับคู่เพียงศูนย์ครั้งหรือครั้งเดียวหรือไม่? แต่ไม่เกินหนึ่งครั้ง? มีแน่นอน. "ทางเลือก" ?คือตัวปรับแต่งที่จับคู่ศูนย์หรืออักขระตัวใดตัวหนึ่งที่อยู่ข้างหน้า แต่ไม่มากกว่านั้น:
รูปแบบ: \d+\.?\d*[KMGT]B 
สตริง: 1.. 3KB 5...GB .. 6TB 
ตรงกัน:     ^^^ ^^^ 
( ตัวอย่าง ) เราเข้าใกล้วิธีแก้ปัญหามากขึ้นแล้ว แต่นี่ไม่ใช่สิ่งที่เราต้องการ เราจะดูวิธีแก้ไขปัญหานี้ในไม่กี่ขั้นตอนในภายหลัง

ในระหว่างนี้ เรามาแก้ไขปัญหานี้กัน:

ในภาษาการเขียนโปรแกรมบางภาษา (เช่น Java) ตัวเลขจำนวนเต็มและจำนวนจุดลอยตัว (จุด) บางตัวอาจตามด้วยl/ Lและf/ Fเพื่อระบุว่าควรถือเป็นค่า long/float (ตามลำดับ) แทนที่จะเป็น int/double ปกติ ค้นหาตัวเลข "ยาว" ที่ถูกต้องทั้งหมดในบรรทัดด้านล่าง:
ลวดลาย:
สาย:   13Lยาว2l 19 L lL 0 
นัด: ^^^ ^^ ^^ ^ 
( สารละลาย )

ขั้นตอนที่ 10: เครื่องหมาย "หรือ"|

RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ส่วนที่ 2 - 4ในขั้นตอนที่ 8 เราประสบปัญหาในการค้นหาตัวเลขทศนิยมประเภทต่างๆ:
รูปแบบ: \d*\.\d+ 
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 
ตรงกัน: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^  
รูปแบบด้านบนจะจับคู่ตัวเลขที่มีจุดทศนิยมและมีตัวเลขอย่างน้อยหนึ่งหลักทางด้านขวาของจุดทศนิยม แต่จะเกิดอะไรขึ้นถ้าเราต้องการจับคู่สตริงเช่น0.? (ไม่มีตัวเลขทางด้านขวาของจุดทศนิยม) เราสามารถเขียนนิพจน์ทั่วไปได้ดังนี้:
รูปแบบ: \d*\.\d* 
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. . 
ตรงกัน: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^ ^^ ^ 
( ตัวอย่าง ) สิ่งนี้ตรงกัน0.แต่ยังตรงกับจุดเดียว.ดังที่คุณเห็นด้านบน จริงๆ แล้วสิ่งที่เราพยายามจับคู่คือคลาสสตริงที่แตกต่างกันสองคลาส:
  1. ตัวเลขที่มีหลักทางด้านขวาของจุดทศนิยมอย่างน้อยหนึ่งหลัก
  2. ตัวเลขที่มีจุดทศนิยมทางซ้ายอย่างน้อยหนึ่งหลัก
เรามาเขียนนิพจน์ทั่วไป 2 นิพจน์ต่อไปนี้โดยไม่แยกจากกัน:
รูปแบบ: \d*\.\d+ 
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. .
แมตช์: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^  
รูปแบบ: \d+\.\d* 
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. .
ตรงกัน: ^^^^^ ^^^ ^^^^ ^^^^^ ^^^^^^^ ^^ 
เราเห็นว่าในกรณีเหล่านี้ สตริงย่อย42, 5หรือ6ไม่.พบโดยเอ็นจิ้น เพื่อให้ได้ผลลัพธ์ที่ต้องการ การรวมนิพจน์ทั่วไปเหล่านี้เข้าด้วยกันจะไม่เสียหาย เราจะบรรลุเป้าหมายนี้ได้อย่างไร? เครื่องหมาย "หรือ" |ช่วยให้เราสามารถระบุลำดับการจับคู่ที่เป็นไปได้หลายลำดับพร้อมกันในนิพจน์ทั่วไป เช่นเดียวกับที่[]เครื่องหมาย "หรือ" ช่วยให้เราสามารถระบุอักขระเดี่ยวทางเลือกได้|เราก็สามารถระบุนิพจน์ทางเลือกแบบหลายอักขระได้ ตัวอย่างเช่น หากเราต้องการค้นหา "สุนัข" หรือ "แมว" เราสามารถเขียนได้ดังนี้:
รูป แบบ: \w\ w \ w 
string:   แน่นอนสุนัขเป็นสัตว์เลี้ยงที่ดีกว่าแมว
ตรงกัน: ^^^^^^^^^ ^^^ ^^^^^^ ^^^ ^^^ ^^^ 
( ตัวอย่าง ) ... แต่สิ่งนี้ตรงกับลำดับอักขระสามตัวทั้งหมดของคลาส "word" แต่ "สุนัข" และ "แมว" ไม่มีตัวอักษรที่เหมือนกันด้วยซ้ำ ดังนั้นวงเล็บเหลี่ยมจึงไม่ช่วยเราในที่นี้ ต่อไปนี้เป็นนิพจน์ทั่วไปที่ง่ายที่สุดที่เราสามารถใช้ได้ซึ่งตรงกับทั้งสองคำนี้เท่านั้น:
รูปแบบ: dog|cat 
string: แน่นอนว่าสุนัขเป็นสัตว์เลี้ยงที่ดีกว่าแมว
ตรงกัน:               ^^^ ^^^ 
( ตัวอย่าง ) ขั้นแรกกลไกของนิพจน์ทั่วไปจะพยายามจับคู่ลำดับทั้งหมดทางด้านซ้ายของอักขระ|แต่ถ้าไม่สำเร็จ ระบบจะพยายามจับคู่ลำดับทางด้านขวาของ|อักขระ อักขระหลายตัว|สามารถเชื่อมโยงกันเพื่อให้ตรงกับลำดับทางเลือกมากกว่าสองลำดับ:
รูป แบบ: dog|cat|pet 
string: แน่นอนว่าสุนัขเป็นสัตว์เลี้ยง ที่ดี กว่าแมว
ตรงกัน:               ^^^ ^^^ ^^^ 
( ตัวอย่าง )

ตอนนี้เรามาแก้ไขปัญหาอีกสองสามข้อเพื่อทำความเข้าใจขั้นตอนนี้ให้ดียิ่งขึ้น:

ใช้เครื่องหมาย|เพื่อแก้ไขนิพจน์ทั่วไปทศนิยมด้านบนเพื่อให้ได้ผลลัพธ์ดังนี้:
ลวดลาย:
สตริง:   0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. .
ตรงกัน: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^ ^^ 
( วิธีแก้ไข ) ใช้เครื่องหมาย คลาส|อักขระ "ทางเลือก" ?ฯลฯ เพื่อสร้างนิพจน์ทั่วไปเดียวที่ตรงกับทั้งจำนวนเต็มและจำนวนจุดลอยตัว (จุด) ตามที่กล่าวไว้ในปัญหาในตอนท้ายของขั้นตอนก่อนหน้า (ปัญหานี้เล็กน้อย) ซับซ้อนกว่านั้นใช่ ;))
ลวดลาย:
สาย:   42L 12 x 3.4f 6l 3.3 0F LF .2F 0. 
ตรงกัน: ^^^ ^^ ^^^^ ^^ ^^^ ^^ ^^^ ^^  
( วิธีแก้ไข ) 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 3 RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ตอนที่ 4
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION