การเรียนรู้นิพจน์ทั่วไป [ปิด]


166

ฉันไม่เข้าใจนิพจน์ทั่วไปจริงๆ คุณช่วยอธิบายพวกเขาให้ฉันฟังได้ง่ายๆ หากมีเครื่องมือหรือหนังสือออนไลน์คุณสามารถลิงก์ไปยังพวกเขาได้หรือไม่?

คำตอบ:


789

ส่วนที่สำคัญที่สุดคือแนวคิด เมื่อคุณเข้าใจการทำงานของ Building Block แล้วความแตกต่างของจำนวนไวยากรณ์จะมากกว่าภาษาถิ่นเล็กน้อย เลเยอร์ด้านบนของไวยากรณ์เอ็นจินนิพจน์ปกติของคุณคือไวยากรณ์ของภาษาการเขียนโปรแกรมที่คุณใช้ ภาษาเช่น Perl ลบภาวะแทรกซ้อนนี้ส่วนใหญ่ แต่คุณจะต้องคำนึงถึงข้อควรพิจารณาอื่น ๆ หากคุณใช้นิพจน์ปกติในโปรแกรม C

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

เริ่มง่ายๆ

แนวคิดการแสดงผลปกติที่ง่ายที่สุดคือตัวอักษร รูปแบบNตรงกับอักขระ 'N'

นิพจน์ปกติถัดจากลำดับการจับคู่ซึ่งกันและกัน ตัวอย่างเช่นรูปแบบที่Nickตรงกับลำดับ 'N' ตามด้วย 'i' ตามด้วย 'c' ตามด้วย 'k'

หากคุณเคยใช้grepกับ Unix - เพียงเพื่อค้นหาสตริงการค้นหาทั่วไป - คุณใช้นิพจน์ปกติอยู่แล้ว! ( reในgrepหมายถึงนิพจน์ทั่วไป)

สั่งซื้อจากเมนู

เพิ่มความซับซ้อนเพียงเล็ก ๆ น้อย ๆ ที่คุณสามารถตรงกับทั้ง 'นิค' หรือ 'นิค' [Nn]ickกับรูปแบบ ส่วนในวงเล็บเหลี่ยมเป็นคลาสอักขระซึ่งหมายความว่าตรงกับหนึ่งในอักขระที่ล้อมรอบ นอกจากนี้คุณยังสามารถใช้ช่วงในคลาสของตัวละครดังนั้น[a-c]ตรงกับ 'a' หรือ 'b' หรือ 'c'

รูปแบบ.พิเศษ: มากกว่าตรงกับจุดที่แท้จริงเท่านั้นมันตรงกับใด ๆของตัวละคร† [-.?+%$A-Za-z0-9...]มันเป็นแนวคิดเดียวกับตัวอักษรระดับใหญ่จริงๆ

นึกถึงคลาสของตัวละครเป็นเมนู: เลือกเพียงอันเดียว

ทางลัดที่เป็นประโยชน์

การใช้.ช่วยให้คุณประหยัดการพิมพ์จำนวนมากและมีทางลัดอื่น ๆ สำหรับรูปแบบทั่วไป สมมติว่าคุณต้องการจับคู่ตัวเลข: วิธีหนึ่งในการเขียนนั่นคือ[0-9]วิธีหนึ่งที่จะเขียนว่าเป็น ตัวเลขเป็นเป้าหมายการจับคู่บ่อยๆดังนั้นคุณสามารถใช้ทางลัดแทน\dได้ ส่วนอื่น ๆ คือ\s(ช่องว่าง) และ\w(ตัวอักษรคำ: ตัวอักษรและตัวเลขหรือขีดล่าง)

ตัวแปรที่เป็นตัวพิมพ์ใหญ่เป็นการเติมเต็มดังนั้น \Sจับคู่กับอักขระที่ไม่ใช่สีขาวใด ๆตัวอย่างเช่น

ครั้งเดียวไม่เพียงพอ

จากนั้นคุณสามารถทำซ้ำส่วนของรูปแบบของคุณกับปริมาณ ตัวอย่างเช่นรูปแบบab?cตรงกับ 'abc' หรือ 'ac' เนื่องจาก?ตัวขยายทำให้รูปแบบย่อยมีการแก้ไขทางเลือก ปริมาณอื่น ๆ

  • * (ศูนย์หรือมากกว่านั้น)
  • + (หนึ่งครั้งขึ้นไป)
  • {n}( nแน่นอนครั้ง)
  • {n,}(อย่างน้อยnครั้ง)
  • {n,m}(อย่างน้อยnครั้ง แต่ไม่เกินmครั้ง)

ใส่บางส่วนของบล็อกเหล่านี้ร่วมกันแบบ[Nn]*ickตรงทั้งหมด

  • ick
  • กรงขัง
  • กรงขัง
  • Nnick
  • nNick
  • nnick
  • (และอื่น ๆ )

นัดแรกแสดงให้เห็นถึงบทเรียนสำคัญ: *ประสบความสำเร็จเสมอ!รูปแบบใด ๆ สามารถจับคู่กับศูนย์ครั้ง

ตัวอย่างที่มีประโยชน์อื่น ๆ :

  • [0-9]+ (และมันเทียบเท่า \d+ ) ตรงกับจำนวนเต็มใด ๆ ที่ไม่เป็นลบ
  • \d{4}-\d{2}-\d{2} ตรงกับวันที่จัดรูปแบบเช่น 2019-01-01

การจัดกลุ่ม

ปริมาณปรับเปลี่ยนรูปแบบไปทางซ้ายทันที คุณอาจคาดหวัง0abc+0เพื่อให้ตรงกับ '0abc0', '0abcabc0' และอื่น ๆ แต่รูปแบบทันทีcไปทางซ้ายของบวกปริมาณคือ ซึ่งหมายความว่า0abc+0ตรงกับ '0abc0', '0abcc0', '0abccc0' และอื่น ๆ

เพื่อให้ตรงกับหนึ่งหรือมากกว่าลำดับของ 'abc' 0(abc)+0ด้วยศูนย์ที่ปลายการใช้ วงเล็บแสดงรูปแบบย่อยที่สามารถวัดเป็นหน่วยได้ นอกจากนี้ยังเป็นเรื่องธรรมดาสำหรับเอ็นจิ้นนิพจน์ทั่วไปเพื่อบันทึกหรือ "จับ" ส่วนของข้อความอินพุตที่ตรงกับกลุ่มที่วงเล็บ การแตกบิตด้วยวิธีนี้มีความยืดหยุ่นมากกว่าและมีข้อผิดพลาดน้อยกว่าการนับดัชนีและsubstrสกัดบิตวิธีนี้มีความยืดหยุ่นมากขึ้นและข้อผิดพลาดน้อยกว่าดัชนีนับและ

การสลับกัน

ก่อนหน้านี้เราเห็นวิธีหนึ่งในการจับคู่ 'Nick' หรือ 'nick' Nick|nickอีกประการหนึ่งคือมีการสลับกันในขณะที่ โปรดจำไว้ว่าการสลับนั้นรวมทุกอย่างทางด้านซ้ายและทุกอย่างไปทางขวา ใช้การจัดกลุ่มวงเล็บที่จะ จำกัด ขอบเขตของ|, เช่น(Nick|nick) ,

สำหรับตัวอย่างอื่นคุณสามารถเขียน[a-c]เป็นa|b|cแต่ตอนนี้มีแนวโน้มที่จะก่อให้เกิดผลลัพธ์เพราะการใช้งานจำนวนมากถือว่าทางเลือกที่จะมีความยาวมากกว่า 1

หนี

แม้ว่าตัวละครบางตัวตรงกับตัวเอง แต่คนอื่น ๆ มีความหมายพิเศษ รูปแบบที่\d+ไม่ตรงกับทับขวาตามด้วยตัวพิมพ์เล็ก D \\d\+ตามด้วยเครื่องหมายบวกที่จะได้รับที่เราต้องการใช้ แบ็กสแลชจะลบความหมายพิเศษออกจากอักขระต่อไปนี้

ความตะกละ

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

ตัวอย่างเช่นสมมติว่าอินพุตเป็น

"สวัสดี" เธอพูด "คุณสบายดีไหม"

คุณอาจคาดหวังว่า".+"จะจับคู่เฉพาะ 'สวัสดี' และจะประหลาดใจเมื่อคุณเห็นว่าตรงกับ 'สวัสดี' ตลอดเวลาผ่าน 'คุณ?'

หากต้องการเปลี่ยนจากความโลภเป็นสิ่งที่คุณคิดว่าระมัดระวังให้เพิ่มส่วนพิเศษ?เข้ากับปริมาณ ตอนนี้คุณเข้าใจแล้วว่า\((.+?)\)ตัวอย่างจากคำถามของคุณทำงานอย่างไร มันตรงกับลำดับของวงเล็บซ้ายที่แท้จริงตามด้วยอักขระหนึ่งตัวขึ้นไปและถูกยกเลิกด้วยวงเล็บขวา

หากอินพุตของคุณคือ '(123) (456)' การจับภาพแรกจะเป็น '123' ควอนตัมที่ไม่ใช่โลภต้องการอนุญาตให้ส่วนที่เหลือของรูปแบบเริ่มจับคู่โดยเร็วที่สุด

(สำหรับความสับสนของคุณฉันไม่รู้ภาษาถิ่นปกติที่((.+?))จะทำสิ่งเดียวกันฉันสงสัยว่ามีบางสิ่งบางอย่างหลงหายในการส่งสัญญาณไปที่ไหนสักแห่งระหว่างทาง)

แองเคอ

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

สมมติว่าคุณต้องการจับคู่ความคิดเห็นของแบบฟอร์ม

-- This is a comment --

^--\s+(.+)\s+--$คุณต้องการเขียน

สร้างของคุณเอง

นิพจน์ทั่วไปนั้นวนซ้ำดังนั้นเมื่อคุณเข้าใจกฎพื้นฐานเหล่านี้แล้วคุณสามารถรวมเข้าด้วยกันได้ตามต้องการ

เครื่องมือสำหรับการเขียนและการดีบัก regexes:

หนังสือ

ทรัพยากรฟรี

เชิงอรรถ

†:ข้อความข้างต้นที่.ตรงกับตัวละครใด ๆ เป็นการทำให้เข้าใจง่ายสำหรับวัตถุประสงค์การสอนที่ไม่เป็นความจริงอย่างเคร่งครัด Dot จับคู่อักขระใด ๆ ยกเว้นการขึ้นบรรทัดใหม่"\n"แต่ในทางปฏิบัติคุณไม่ค่อยคาดหวังรูปแบบเช่น.+การข้ามขอบเขตการขึ้นบรรทัดใหม่ Perl regexes มี/sสวิตช์และ Java Pattern.DOTALLตัวอย่างเช่นเพื่อให้.ตรงกับตัวละครใด ๆ เลย สำหรับภาษาที่ไม่มีคุณลักษณะดังกล่าวคุณสามารถใช้สิ่งที่ต้องการ[\s\S]จับคู่ "ช่องว่างใด ๆ หรือช่องว่างที่ไม่ใช่" ในคำอื่น ๆ


14
นอกจากนี้คุณยังสามารถใช้วิธีการทดลองและข้อผิดพลาดและการติดตามตัวทดสอบ regex ออนไลน์และตัวดีบักสามารถช่วยได้มาก: regex101.com
Juraj.Lorinc

2
มันจะเป็นมูลค่าการกล่าวขวัญว่าแม้จะเป็นรูปแบบที่คล้ายกันa{,m}ไม่ได้เป็นอย่างน้อยใน Javascript, Perl และ Python
คดีฟ้องร้องกองทุนโมนิก้า

2
มันจะมีค่ามากที่จะกล่าวถึงว่ามีเอ็นจิ้นนิพจน์ทั่วไปที่แตกต่างกันซึ่งทั้งหมดมีกฎของชุดคุณลักษณะและกฎเกี่ยวกับวากยสัมพันธ์ที่แตกต่างกัน
hek2mgl

1
hackr.io/tutorials/learn-regular-expressions-regexเป็นสถานที่ที่ดีในการค้นหาบทเรียนออนไลน์ regex ที่ดีที่สุด บทเรียนทั้งหมดที่นี่จะถูกส่งและแนะนำ (upvoted like SO) โดยชุมชนการเขียนโปรแกรม
Saurabh Hooda

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