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

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

เผยแพร่ในกลุ่ม
RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 1 RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 2 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป ส่วนที่ 3 ส่วนสุดท้ายตรงกลางนี้จะกล่าวถึงสิ่งต่างๆ ที่ผู้เชี่ยวชาญด้านนิพจน์ทั่วไปใช้เป็นหลัก แต่เนื้อหาจากภาคก่อนๆ มันง่ายสำหรับคุณใช่ไหมล่ะ? ซึ่งหมายความว่าคุณสามารถจัดการวัสดุนี้ได้อย่างง่ายดายเช่นเดียวกัน! ต้นฉบับที่นี่ RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ตอนที่ 4 - 1 <h2>ขั้นตอนที่ 16: กลุ่มที่ไม่มีการบันทึก(?:)</h2> RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ตอนที่ 4 - 2ในสองตัวอย่างในขั้นตอนที่แล้ว เรากำลังบันทึกข้อความที่เราไม่ต้องการจริงๆ ในงานขนาดไฟล์ เราได้บันทึกช่องว่างก่อนตัวเลขตัวแรกของขนาดไฟล์ และในงาน CSV เราได้บันทึกเครื่องหมายจุลภาคระหว่างแต่ละโทเค็น เราไม่จำเป็นต้องจับอักขระเหล่านี้ แต่เราจำเป็นต้องใช้พวกมันเพื่อจัดโครงสร้างนิพจน์ทั่วไปของเรา นี่เป็นตัวเลือกที่เหมาะสมที่สุดสำหรับการใช้กลุ่มโดยไม่ต้องจับ(?:)ภาพ กลุ่มที่ไม่ได้จับภาพทำหน้าที่เหมือนอย่างที่ฟังทุกประการ โดยอนุญาตให้จัดกลุ่มอักขระและใช้ในนิพจน์ทั่วไปได้ แต่ไม่ได้จับภาพอักขระเหล่านั้นในกลุ่มที่มีหมายเลข:
pattern: (?:")([^"]+)(?:") string 
: ฉันต้องการ"ข้อความที่อยู่ในเครื่องหมายคำพูดเหล่านี้" เท่านั้น
การแข่งขัน:             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
กลุ่ม:                 1111111111111111111111111111    
( ตัวอย่าง ) ขณะนี้นิพจน์ทั่วไปจับคู่ข้อความที่ยกมาและอักขระเครื่องหมายคำพูดด้วย แต่กลุ่มที่จับภาพจะบันทึกเฉพาะข้อความที่ยกมาเท่านั้น ทำไมเราควรทำเช่นนี้? ประเด็นก็คือเอ็นจิ้นนิพจน์ทั่วไปส่วนใหญ่อนุญาตให้คุณกู้คืนข้อความจากกลุ่มการบันทึกที่กำหนดไว้ในนิพจน์ทั่วไปของคุณ หากเราสามารถตัดอักขระพิเศษที่เราไม่ต้องการโดยไม่ต้องรวมไว้ในกลุ่มจับภาพของเราได้ จะทำให้แยกวิเคราะห์และจัดการข้อความได้ง่ายขึ้นในภายหลัง ต่อไปนี้เป็นวิธีล้างตัวแยกวิเคราะห์ CSV จากขั้นตอนก่อนหน้า:
รูปแบบ: (?:^|,)\s*(?:\"([^",]*)\"|([^", ]*)) 
สตริง:   a , " b ", " cd ", e , f , " gh ", dfgi ,, k , "", l 
ตรงกัน: ^ ^ ^^^ ^ ^ ^^^ ^^^ ^ ^ 
กลุ่ม:    2 1 111 2 2 111 2222 2 2    
( ตัวอย่าง ) มีบางสิ่งที่ควร <mark>สังเกตที่นี่:</mark> ประการแรก เราจะไม่จับลูกน้ำอีกต่อไปเนื่องจากเราเปลี่ยนกลุ่มที่จับภาพ เป็น กลุ่ม(^|,)ที่ไม่จับภาพ (?:^|,)ประการที่สอง เราซ้อนกลุ่มแคปเจอร์ไว้ภายในกลุ่มที่ไม่ใช่แคปเจอร์ สิ่งนี้มีประโยชน์เมื่อคุณต้องการให้กลุ่มอักขระปรากฏในลำดับเฉพาะ แต่คุณสนใจเพียงชุดย่อยของอักขระเหล่านั้นเท่านั้น ในกรณีของเรา เราจำเป็นต้องมี อักขระ ที่ไม่ใช่เครื่องหมายคำพูดและเครื่องหมายจุลภาคเพื่อให้ปรากฏในเครื่องหมายคำพูด แต่จริงๆ แล้วเราไม่จำเป็นต้องมีอักขระเครื่องหมายคำพูด ดังนั้นจึงไม่จำเป็นต้องบันทึกอักขระเหล่านั้น สุดท้ายนี้ <mark>หมายเหตุ</mark> ว่าในตัวอย่างข้างต้น ยังมีการจับคู่ที่มีความ ยาวเป็นศูนย์ระหว่างอักขระและ เครื่องหมายคำพูดเป็นสตริงย่อยที่ค้นหา แต่ไม่มีอักขระระหว่างเครื่องหมายคำพูด ดังนั้นสตริงย่อยที่ตรงกันจึงไม่มีอักขระ (ความยาวเป็นศูนย์) <h3>เราจะรวบรวมความรู้ของเราหรือไม่? ต่อไปนี้เป็นงานสองครึ่งครึ่งที่จะช่วยเราในเรื่องนี้:</h3> การใช้กลุ่มที่ไม่ได้จับภาพ (และการจับกลุ่ม และคลาสอักขระ ฯลฯ) เขียนนิพจน์ทั่วไปที่รวบรวมเฉพาะขนาดไฟล์ที่มีรูปแบบถูกต้องในบรรทัด ด้านล่าง : [^",]*kl""
ลวดลาย:
สตริง:   6.6KB 1..3KB 12KB 5G 3.3MB KB .6.2TB 9MB
ตรงกัน: ^^^^^ ^^^^^ ^^^^^^ ^^^^ 
กลุ่ม:    11111 1111 11111 111    
( แนวทางแก้ไข ) แท็กเปิด HTML ขึ้นต้นด้วย<และลงท้าย>ด้วย แท็ กปิด HTML เริ่มต้นด้วยลำดับอักขระ</และลงท้ายด้วยอักขระ >ชื่อแท็กอยู่ระหว่างอักขระเหล่านี้ คุณสามารถเขียนนิพจน์ทั่วไปเพื่อจับเฉพาะชื่อในแท็กต่อไปนี้ได้หรือไม่ (คุณอาจแก้ไขปัญหานี้ได้โดยไม่ต้องใช้กลุ่มที่ไม่จับภาพ ลองแก้ปัญหาสองวิธีนี้! ครั้งหนึ่งกับกลุ่มและอีกครั้งไม่มี)
ลวดลาย:
สตริง:   <p> </span> <div> </kbd> <link> 
ตรงกัน: ^^^ ^^^^^^ ^^^^^ ^^^^^^ ^^^^^^ 
กลุ่ม:    1 1111 111 111 1111    
( โซลูชันโดยใช้กลุ่มที่ไม่จับภาพ ) ( โซลูชันโดยไม่ต้องใช้กลุ่มที่ไม่จับภาพ ) <h2>ขั้นตอนที่ 17: ลิงก์ย้อนกลับ\Nและกลุ่มการจับที่มีชื่อ</h2> RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ตอนที่ 4 - 3แม้ว่าฉันจะเตือนคุณในบทนำว่าพยายามสร้างตัวแยกวิเคราะห์ HTML โดยใช้นิพจน์ทั่วไป นำไปสู่ความโศกเศร้า ตัวอย่างสุดท้ายนี้เป็นการต่อยอดไปยังคุณลักษณะที่มีประโยชน์ (บางครั้ง) ของนิพจน์ทั่วไปส่วนใหญ่: backreferences ลิงก์ย้อนกลับเป็นเหมือนกลุ่มที่ทำซ้ำซึ่งคุณสามารถพยายามจับข้อความเดียวกันสองครั้ง แต่มีความแตกต่างกันในแง่มุมที่สำคัญอย่างหนึ่ง - พวกเขาจะจับเฉพาะข้อความเดียวกันทีละตัวอักษรเท่านั้น ในขณะที่กลุ่มที่ทำซ้ำจะช่วยให้เราสามารถจับภาพบางอย่างเช่นนี้:
รูปแบบ: (he(?:[az])+) 
string:   heyabcdefg เฮ้ เฮ้ เฮ้ เฮ้ เหลือง heyyyyyy 
ตรงกัน: ^^^^^^^^^^ ^^^ ^^^^ ^^^^^^^^ ^^^ ^^^^^^^ 
กลุ่ม:    1111111111 111 1111 11111111 11111111111    
( ตัวอย่าง ) ...จากนั้นลิงก์ย้อนกลับจะจับคู่เฉพาะสิ่งนี้:
รูปแบบ: (he([az])(\2+)) 
string: heyabcdefg เฮ้ เฮ้ เฮ้ เฮ้ เหลืองเฮ้ เฮ้ เฮ้ 
ตรงกัน:                              ^^^^^^^^^^^ 
กลุ่ม:                                 11233333333    
( ตัวอย่าง ) การจับกลุ่มซ้ำจะมีประโยชน์เมื่อคุณต้องการจับคู่รูปแบบเดียวกันซ้ำๆ ในขณะที่ลิงก์ย้อนกลับจะมีประโยชน์เมื่อคุณต้องการจับคู่ข้อความเดียวกัน ตัวอย่างเช่น เราสามารถใช้ลิงก์ย้อนกลับเพื่อค้นหาแท็ก HTML เปิดและปิดที่ตรงกัน:
รูปแบบ: <(\w+)[^>]*>[^<]+<\/\1> 
string:   <span style="color: red">เฮ้</span> 
ตรงกัน: ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ 
กลุ่ม:    1111    
( ตัวอย่าง ) <mark>โปรดทราบ</mark> นี่เป็นตัวอย่างที่ง่ายมาก และฉันขอแนะนำอย่างยิ่งให้คุณอย่าพยายามเขียนตัวแยกวิเคราะห์ HTML ที่ใช้นิพจน์ทั่วไป นี่เป็นไวยากรณ์ที่ซับซ้อนมากและอาจทำให้คุณป่วยได้ กลุ่มจับภาพที่มีชื่อนั้นคล้ายคลึงกับลิงก์ย้อนกลับมาก ดังนั้นฉันจะอธิบายสั้นๆ ที่นี่ ข้อแตกต่างระหว่างการอ้างอิงกลับและกลุ่มแคปเจอร์ที่มีชื่อก็คือ... กลุ่มแคปเจอร์ที่มีชื่อมีชื่อ:
รูปแบบ: <(?<tag>\w+)[^>]*>[^<]+<\/(?P=tag)></tag> 
string:   <span style="color: red">เฮ้< /span> 
ตรงกัน: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
กลุ่ม:    1111    
( ตัวอย่าง ) คุณสามารถสร้างกลุ่มการจับภาพที่มีชื่อได้โดยใช้ไวยากรณ์ (?<name>...) หรือ (?'name'...) (นิพจน์ทั่วไปที่เข้ากันได้กับ .NET) หรือด้วยไวยากรณ์นี้ (?P<name> ..) หรือ (?P'name'...) (นิพจน์ทั่วไปที่เข้ากันได้กับ Python) เนื่องจากเราใช้ PCRE (Perl Compatible Regular Expression) ซึ่งรองรับทั้งสองเวอร์ชัน เราจึงใช้เวอร์ชันใดเวอร์ชันหนึ่งได้ที่นี่ (Java 7 คัดลอกไวยากรณ์ .NET แต่เฉพาะเวอร์ชันวงเล็บมุม หมายเหตุของผู้แปล) หากต้องการทำซ้ำกลุ่มการจับภาพที่มีชื่อในภายหลังในนิพจน์ทั่วไป เราใช้ \<kname> หรือ \k'name' (.NET) หรือ (? P= ชื่อ) (หลาม) ขอย้ำอีกครั้งว่า PCRE รองรับตัวเลือกต่าง ๆ เหล่านี้ทั้งหมด คุณสามารถอ่านเพิ่มเติมเกี่ยวกับกลุ่มจับภาพที่มีชื่อได้ที่นี่แต่นี่คือสิ่งที่คุณต้องรู้ส่วนใหญ่เกี่ยวกับกลุ่มเหล่านั้น <h3>งานที่จะช่วยเรา:</h3> ใช้ลิงก์ย้อนกลับเพื่อช่วยฉันจำ... อืม... ชื่อของบุคคลนี้
ลวดลาย:
string: "สวัสดี ฉันชื่อโจ" [ต่อมา] "ผู้ชายคนนั้นชื่ออะไร โจ ?"
การแข่งขัน:        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ↑ 
กลุ่ม:                  111    
( วิธีแก้ไข ) <h2>ขั้นตอนที่ 18: มองไปข้างหน้าและมองข้างหลัง</h2> RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ส่วนที่ 4 - 4ตอนนี้เราจะเจาะลึกถึงคุณลักษณะขั้นสูงบางอย่างของนิพจน์ทั่วไป ฉันใช้ทุกอย่างจนถึงขั้นตอนที่ 16 ค่อนข้างบ่อย แต่ขั้นตอนสุดท้ายเหล่านี้มีไว้สำหรับผู้ที่ใช้ regex อย่างจริงจังเพื่อจับคู่นิพจน์ที่ซับซ้อนมากเท่านั้น กล่าวอีกนัยหนึ่ง ผู้เชี่ยวชาญด้านการแสดงออกปกติ “มองไปข้างหน้า” และ “มองย้อนหลัง” อาจดูซับซ้อน แต่ก็ไม่ได้ซับซ้อนเกินไป ช่วยให้คุณสามารถทำสิ่งที่คล้ายกับที่เราทำกับกลุ่มที่ไม่ได้จับภาพก่อนหน้านี้ - ตรวจสอบว่ามีข้อความใดๆ อยู่ข้างหน้าหรือหลังข้อความจริงที่เราต้องการจับคู่ทันทีหรือไม่ ตัวอย่างเช่น สมมติว่าเราต้องการจับคู่เฉพาะชื่อของสิ่งที่ผู้คนชอบ แต่เฉพาะในกรณีที่พวกเขากระตือรือร้นเกี่ยวกับมัน (เฉพาะในกรณีที่พวกเขาจบประโยคด้วยเครื่องหมายอัศเจรีย์) เราสามารถทำอะไรบางอย่างเช่น:
pattern: (\w+)(?=!) 
string: ฉันชอบโต๊ะ ฉันขอขอบคุณที่เย็บกระดาษ ฉันรักโคมไฟ !
ตรงกัน:                                           ^^^^ 
กลุ่ม:                                              1111    
( ตัวอย่าง ) คุณจะเห็นว่า captive group ข้างต้น(\w+)ซึ่งโดยปกติจะตรงกับคำใดๆ ในเนื้อเรื่อง จะจับคู่เฉพาะคำว่า lamp เท่านั้น การมองไปข้างหน้าเชิงบวก(?=!)หมายความว่าเราสามารถจับคู่ลำดับที่ลงท้ายด้วยเท่านั้น!แต่จริงๆ แล้วเราไม่สามารถจับคู่อักขระเครื่องหมายอัศเจรีย์ได้ นี่เป็นข้อแตกต่างที่สำคัญ เนื่องจากในกลุ่มที่ไม่ได้จับ เราจะจับคู่ตัวละครแต่ไม่ได้จับมัน ด้วย lookaheads และ lookbehinds เราใช้อักขระเพื่อสร้างการแสดงออกปกติของเรา แต่แล้วเราก็ไม่สามารถเทียบเคียงกับตัวมันเองได้ เราสามารถจับคู่มันได้ในภายหลังในนิพจน์ทั่วไปของเรา lookahead และ lookbehind มีสี่ประเภท: lookahead เชิงบวก (?=...), lookahead เชิงลบ (?!...), lookahead เชิงบวก (?<=...) และ lookahead เชิงลบ (?<!. ..) . พวกเขาทำในสิ่งที่พวกเขาดูเหมือน - lookahead และ lookbehind เชิงบวกทำให้เอ็นจิ้นนิพจน์ทั่วไปจับคู่ต่อเมื่อข้อความที่อยู่ใน lookahead/lookbehind ตรงกันเท่านั้น lookahead และ lookbehind เชิงลบจะทำตรงกันข้าม - อนุญาตให้ regex จับคู่เฉพาะเมื่อข้อความที่อยู่ใน lookahead/lookbehind ไม่ตรงกัน ตัวอย่างเช่น เราต้องการจับคู่ชื่อเมธอดเฉพาะในลำดับเมธอดต่อเนื่องกัน ไม่ใช่วัตถุที่ชื่อเมธอดทำงาน ในกรณีนี้ แต่ละชื่อเมธอดจะต้องนำหน้าด้วย.. นิพจน์ทั่วไปที่ใช้การมองย้อนกลับแบบธรรมดาสามารถช่วยได้ที่นี่:
รูปแบบ: (?<=\.)(\w+) 
สตริง: myArray. flatMap.aggregate.summarise.print !
การแข่งขัน:         ^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^ 
กลุ่ม:            1111111 111111111 111111111 11111    
( ตัวอย่าง ) ในข้อความข้างต้น เราจะจับคู่ลำดับของอักขระคำใดๆ\w+แต่ต้องนำหน้าด้วยอักขระ.เท่านั้น เราสามารถบรรลุสิ่งที่คล้ายกันได้โดยใช้กลุ่มที่ไม่จับภาพ แต่ผลลัพธ์ที่ได้จะยุ่งกว่าเล็กน้อย:
รูปแบบ: (?:\.)(\w+) 
สตริง: myArray .flatMap.aggregate.summarise.print !
การแข่งขัน:        ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^ 
กลุ่ม:            1111111 111111111 111111111 11111    
( ตัวอย่าง ) แม้ว่าจะสั้นกว่า แต่ก็ตรงกับอักขระที่เราไม่ต้องการ แม้ว่าตัวอย่างนี้อาจดูไม่สำคัญ แต่การมองไปข้างหน้าและการมองข้างหลังสามารถช่วยเราจัดระเบียบนิพจน์ทั่วไปของเราได้จริงๆ <h3>เหลืออีกน้อยมากจะจบแล้ว! 2 งานต่อไปนี้จะนำเราเข้าใกล้มันมากขึ้นอีก 1 ก้าว:</h3> Negative lookbehind (?<!...) ช่วยให้กลไกนิพจน์ทั่วไปพยายามค้นหารายการที่ตรงกันต่อไปเฉพาะในกรณีที่ข้อความที่อยู่ภายใน lookbehind เชิงลบไม่ใช่ แสดงจนกระทั่งข้อความที่เหลือ ซึ่งคุณต้องค้นหารายการที่ตรงกัน ตัวอย่างเช่น เราสามารถใช้นิพจน์ทั่วไปเพื่อจับคู่เฉพาะนามสกุลของผู้หญิงที่เข้าร่วมการประชุมเท่านั้น ในการดำเนินการนี้ เราต้องการให้แน่ใจว่านามสกุลของบุคคลนั้นไม่ได้นำหน้าด้วยMr.. คุณสามารถเขียนนิพจน์ทั่วไปสำหรับสิ่งนี้ได้หรือไม่? (นามสกุลสามารถสันนิษฐานได้ว่ามีความยาวอย่างน้อยสี่ตัวอักษร)
ลวดลาย:
สาย: นาย. บราวน์, นางสาว. สมิธ , นาง. โจนส์ , นางสาวเดซี่ , มิสเตอร์. สีเขียว
ตรงกัน:                ^^^^^ ^^^^^ ^^^^^ 
กลุ่ม:                   11111 11111 11111    
( วิธีแก้ไข ) สมมติว่าเรากำลังล้างฐานข้อมูลและเรามีคอลัมน์ข้อมูลที่แสดงถึงเปอร์เซ็นต์ น่าเสียดายที่บางคนเขียนตัวเลขเป็นค่าทศนิยมในช่วง [0.0, 1.0] ในขณะที่บางคนเขียนเปอร์เซ็นต์ในช่วง [0.0%, 100.0%] และบางคนก็เขียนค่าเปอร์เซ็นต์แต่ลืมเครื่องหมายเปอร์เซ็นต์ตามตัว%อักษร การใช้ lookahead เชิงลบ (?!...) คุณสามารถทำเครื่องหมายเฉพาะค่าที่ควรเป็นเปอร์เซ็นต์แต่ตัวเลขหายไปได้%หรือไม่ สิ่งเหล่านี้จะต้องเป็นค่าที่มากกว่า 1.00 อย่างเคร่งครัด แต่ไม่มีส่วนต่อ%ท้าย (ไม่มีตัวเลขใดที่สามารถมีตัวเลขมากกว่าสองหลักก่อนหรือหลังจุดทศนิยม) <mark>หมายเหตุ</mark> ว่าวิธีแก้ปัญหานี้ยากมาก หากคุณสามารถแก้ปัญหานี้ได้โดยไม่ต้องดูคำตอบของฉัน แสดงว่าคุณมีทักษะมากมายในนิพจน์ทั่วไปแล้ว!
ลวดลาย:
สตริง: 0.32 100.00 5.6 0.27 98% 12.2% 1.01 0.99% 0.99 13.13 1.10 
ตรงกัน:      ^^^^^^ ^^^ ^^^^ ^^^^^ ^^^^ 
กลุ่ม:         111111 111 1111 11111 1111    
( วิธีแก้ไข ) <h2>ขั้นตอนที่ 19: เงื่อนไขในนิพจน์ทั่วไป</h2> RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ตอนที่ 4 - 5ตอนนี้เรามาถึงจุดที่คนส่วนใหญ่จะไม่ใช้นิพจน์ทั่วไปอีกต่อไป เราได้ครอบคลุมกรณีการใช้งานประมาณ 95% สำหรับนิพจน์ทั่วไปอย่างง่าย และโดยทั่วไปแล้วทุกสิ่งที่ทำในขั้นตอนที่ 19 และ 20 จะทำโดยใช้ภาษาการจัดการข้อความที่มีคุณลักษณะครบถ้วนมากกว่า เช่น awk หรือ sed (หรือภาษาการเขียนโปรแกรมสำหรับวัตถุประสงค์ทั่วไป) ที่กล่าวว่า มาดูกันต่อไปเพื่อให้คุณรู้ว่านิพจน์ทั่วไปสามารถทำอะไรได้บ้าง แม้ว่านิพจน์ทั่วไปจะไม่ใช่ทัวริงที่สมบูรณ์แต่เอ็นจิ้นนิพจน์ทั่วไปบางตัวก็มีคุณสมบัติที่คล้ายคลึงกับภาษาการเขียนโปรแกรมที่สมบูรณ์มาก คุณลักษณะอย่างหนึ่งคือ "เงื่อนไข" เงื่อนไข Regex อนุญาตให้ใช้คำสั่ง if-then-else โดยที่สาขาที่เลือกจะถูกกำหนดโดย "มองไปข้างหน้า" หรือ "มองย้อนกลับไป" ที่เราได้เรียนรู้ในขั้นตอนที่แล้ว ตัวอย่างเช่น คุณอาจต้องการจับคู่เฉพาะรายการที่ถูกต้องในรายการวันที่:
รูปแบบ: (?<=Feb )([1-2][0-9])|(?<=Mar )([1-2][0-9]|3[0-1]) 
string: วันที่ทำงาน : ก.พ. 28 , 29 ก.พ. , 30 ก.พ. , 30มี.ค. , 31 มี.ค.  
การแข่งขัน:                   ^^ ^^ ^^ ^^ 
กลุ่ม:                      11 11 22 22    
( ตัวอย่าง ) <mark>หมายเหตุ</mark> ว่ากลุ่มข้างต้นได้รับการจัดทำดัชนีตามเดือนด้วย เราสามารถเขียนนิพจน์ทั่วไปตลอด 12 เดือนและบันทึกเฉพาะวันที่ที่ถูกต้องเท่านั้น ซึ่งจะนำมารวมกันเป็นกลุ่มที่จัดทำดัชนีตามเดือนของปี ข้างต้นใช้โครงสร้างแบบ if-like ที่จะค้นหารายการที่ตรงกันในกลุ่มแรกหาก "Feb" นำหน้าตัวเลข (และในทำนองเดียวกันสำหรับกลุ่มที่สอง) แต่ถ้าเราต้องการใช้การประมวลผลพิเศษเฉพาะในเดือนกุมภาพันธ์ล่ะ? บางอย่างเช่น "หากตัวเลขนำหน้าด้วย "Feb" ให้ทำเช่นนี้ ไม่เช่นนั้นก็ทำอย่างอื่น" ต่อไปนี้เป็นวิธีดำเนินการแบบมีเงื่อนไข:
รูปแบบ: (?(?<=Feb )([1-2][0-9])|([1-2][0-9]|3[0-1])) 
string: วันที่ทำงาน: 28 กุมภาพันธ์ , 29 ก.พ. , 30 ก.พ. , 30 มี.ค. , 31มี.ค.  
การแข่งขัน:                   ^^ ^^ ^^ ^^ 
กลุ่ม:                      11 11 22 22    
( ตัวอย่าง ) โครงสร้าง if-then-else มีลักษณะดังนี้ (?(If)then|else) โดยที่ (if) ถูกแทนที่ด้วย "look forward" หรือ "look back" ในตัวอย่างข้างต้น (ถ้า) เขียนเป็น(?<=Feb). คุณจะเห็นว่าเราจับคู่วันที่ที่มากกว่า 29 แต่เฉพาะในกรณีที่ไม่ตรงกับ "กุมภาพันธ์" การใช้ lookbehinds ในนิพจน์แบบมีเงื่อนไขมีประโยชน์หากคุณต้องการให้แน่ใจว่าข้อความที่ตรงกันนำหน้าด้วยข้อความบางส่วน เงื่อนไข lookahead เชิงบวกอาจทำให้เกิดความสับสนเนื่องจากตัวเงื่อนไขเองไม่ตรงกับข้อความใดๆ ดังนั้น หากคุณต้องการให้เงื่อนไข if มีค่า เงื่อนไขนั้นจะต้องเทียบได้กับ lookahead ดังด้านล่าง:
รูปแบบ: (?(?=exact)exact|else)wo 
string: ตรงทุกประการตรงทุกประการสองอย่างอื่น  
ที่ตรงกัน:            ^^^^^^^ ^^^^^^
( ตัวอย่าง ) ซึ่งหมายความว่าเงื่อนไข lookahead เชิงบวกไม่มีประโยชน์ คุณตรวจสอบเพื่อดูว่าข้อความนั้นอยู่ข้างหน้าหรือไม่ จากนั้นจึงจัดเตรียมรูปแบบที่ตรงกันเพื่อติดตามเมื่อเป็นเช่นนั้น นิพจน์แบบมีเงื่อนไขไม่ได้ช่วยอะไรเราเลย คุณยังสามารถแทนที่ข้อความด้านบนด้วยนิพจน์ทั่วไปที่ง่ายกว่าได้:
รูปแบบ: (?:แน่นอน|else)wo 
สตริง: ตรงทุกประการตรงทุกประการสองอย่างอื่น  
ที่ตรงกัน:            ^^^^^^^ ^^^^^^
( ตัวอย่าง ) ดังนั้น หลักทั่วไปสำหรับนิพจน์แบบมีเงื่อนไขคือ ทดสอบ ทดสอบ และทดสอบอีกครั้ง มิฉะนั้น วิธีแก้ปัญหาที่คุณคิดว่าชัดเจนจะล้มเหลวด้วยวิธีที่น่าตื่นเต้นและคาดไม่ถึง :) <h3>เรามาถึงช่วงสุดท้ายของงานที่แยกเราจากขั้นตอนสุดท้ายที่ 20:</h3> เขียนนิพจน์ทั่วไปที่ ใช้นิพจน์เงื่อนไข lookahead เชิงลบเพื่อทดสอบว่าคำถัดไปขึ้นต้นด้วยตัวพิมพ์ใหญ่หรือไม่ หากเป็นเช่นนั้น ให้หยิบตัวพิมพ์ใหญ่เพียงตัวเดียวตามด้วยตัวพิมพ์เล็ก หากไม่เป็นเช่นนั้น ให้คว้าอักขระคำใดก็ได้
ลวดลาย:
สตริง:   Jones Smith 9sfjn Hobbes 23r4tgr9h CSV Csv vVv 
ตรงกัน: ^^^^^ ^^^^^ ^^^^^ ^^^^^^ ^^^^^^^^^ ^^^ ^^^ 
กลุ่ม:    22222 22222 11111 222222 111111111 222 111    
( วิธีแก้ไข ) เขียน lookbehind นิพจน์เงื่อนไขเชิงลบที่จะจับข้อความownsเฉพาะในกรณีที่ไม่ได้นำหน้าด้วยข้อความและclที่จะจับข้อความoudsเฉพาะเมื่อข้อความอยู่ข้างหน้าเท่านั้น cl(เป็นตัวอย่างเล็กน้อย แต่คุณจะทำอย่างไรได้...)
ลวดลาย:
string: ตัวตลกเหล่านั้นเป็นเจ้าของ cl ouds อู๊ด
ตรงกัน:              ^^^^ ^^^^   
( วิธีแก้ไข ) <h2>ขั้นตอนที่ 20: การเรียกซ้ำและการศึกษาเพิ่มเติม</h2> RegEx: 20 ขั้นตอนสั้นๆ เพื่อเชี่ยวชาญนิพจน์ทั่วไป  ตอนที่ 4 - 6อันที่จริง มีหลายสิ่งหลายอย่างที่สามารถรวมเป็นการแนะนำ 20 ขั้นตอนสำหรับหัวข้อใดก็ได้ และนิพจน์ทั่วไปก็ไม่มีข้อยกเว้น มีการใช้งานและมาตรฐานที่แตกต่างกันมากมายสำหรับนิพจน์ทั่วไปที่สามารถพบได้บนอินเทอร์เน็ต หากคุณต้องการเรียนรู้เพิ่มเติม ฉันขอแนะนำให้คุณลองดูเว็บไซต์ที่เยี่ยมยอดอย่างRegularexpressions.infoซึ่งเป็นข้อมูลอ้างอิงที่ยอดเยี่ยม และแน่นอนว่าฉันได้เรียนรู้มากมายเกี่ยวกับนิพจน์ทั่วไปจากที่นั่น ฉันขอแนะนำเป็นอย่างยิ่ง รวมถึงregex101.comสำหรับการทดสอบและเผยแพร่ผลงานสร้างสรรค์ของคุณ ในขั้นตอนสุดท้ายนี้ ฉันจะให้ความรู้เพิ่มเติมเล็กน้อยเกี่ยวกับนิพจน์ทั่วไป เช่น วิธีเขียนนิพจน์แบบเรียกซ้ำ การเรียกซ้ำแบบธรรมดานั้นค่อนข้างง่าย แต่ลองมาคิดดูว่ามันหมายถึงอะไรในบริบทของนิพจน์ทั่วไป ไวยากรณ์สำหรับการเรียกซ้ำอย่างง่ายในนิพจน์ทั่วไปเขียนดังนี้(?R)?: แต่แน่นอนว่าไวยากรณ์นี้จะต้องปรากฏภายในนิพจน์นั้นเอง สิ่งที่เราจะทำคือซ้อนนิพจน์ไว้ภายในตัวมันเอง โดยไม่จำกัดจำนวนครั้ง ตัวอย่างเช่น:
รูปแบบ: (hey(?R)?oh) 
string:   heyoh heyyoh heyheyohoh hey oh heyhey hey heyheyohoh  
ตรงกัน: ^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ 
group:    11111 1111111111 1111111111    
( ตัวอย่าง ) เนื่องจากนิพจน์ที่ซ้อนกันเป็นทางเลือก ( (?R)ตาม?) การจับคู่ที่ง่ายที่สุดคือการละเว้นการเรียกซ้ำโดยสิ้นเชิง ดังนั้นheyแล้วจึงohจับคู่ ( heyoh) หากต้องการจับคู่นิพจน์ที่ซับซ้อนกว่านี้ เราต้องพบว่าสตริงย่อยที่ตรงกันนั้นซ้อนอยู่ภายในตัวมันเองที่จุดในนิพจน์ที่เราแทรก(?R)ลำดับ กล่าวอีกนัยหนึ่ง เราสามารถหา เฮ้เฮ้โฮโฮ หรือ เฮ้เฮ้โฮโฮโฮ่ และอื่นๆ สิ่งที่ยอดเยี่ยมอย่างหนึ่งเกี่ยวกับนิพจน์ที่ซ้อนกันเหล่านี้ก็คือ ไม่เหมือนกับการอ้างอิงย้อนหลังและกลุ่มการบันทึกที่มีชื่อ ตรงที่ไม่ได้จำกัดคุณไว้เฉพาะข้อความที่คุณจับคู่ก่อนหน้านี้ ทีละอักขระ ตัวอย่างเช่น:
รูปแบบ: ([Hh][Ee][Yy](?R)?oh) 
string:   heyoh heyyoh heyHeYohoh hey oh heyhey heEyHeYHEyohohoh  
ตรงกัน: ^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^ 
กลุ่ม:    11111 1111111111 111111111111111    
( ตัวอย่าง ) คุณสามารถจินตนาการได้ว่าเอ็นจิ้นนิพจน์ทั่วไปคัดลอกและวางนิพจน์ทั่วไปของคุณลงในตัวมันเองตามจำนวนครั้งที่ต้องการ แน่นอนว่านี่หมายความว่าบางครั้งอาจไม่เป็นไปตามที่คุณคาดหวัง:
รูปแบบ: ((?:\(\*)[^*)]*(?R)?(?:\*\))) 
string: (* ความคิดเห็น(* ซ้อนกัน *)ไม่ใช่ *)
การแข่งขัน:            ^^^^^^^^^^^^ 
กลุ่ม:               111111111111    
( ตัวอย่าง ) คุณบอกได้ไหมว่าทำไม regex นี้จึงบันทึกเฉพาะความคิดเห็นที่ซ้อนกันเท่านั้น ไม่ใช่ความคิดเห็นภายนอก สิ่งหนึ่งที่แน่นอนคือ: เมื่อเขียนนิพจน์ทั่วไปที่ซับซ้อน ให้ทดสอบนิพจน์เหล่านี้เสมอเพื่อให้แน่ใจว่านิพจน์ทำงานในแบบที่คุณคิด การชุมนุมความเร็วสูงไปตามถนนแห่งการแสดงออกปกตินี้สิ้นสุดลงแล้ว ฉันหวังว่าคุณจะสนุกกับการเดินทางครั้งนี้ ในที่สุดฉันจะออกจากที่นี่ตามที่ฉันสัญญาไว้ตั้งแต่ต้นลิงก์ที่มีประโยชน์หลายประการสำหรับการศึกษาเนื้อหาในเชิงลึกเพิ่มเติม:
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION