อ่าน 10 นาที
การจับคู่รูปแบบ
ใน วิทยาการคอมพิวเตอร์ การ จับคู่รูปแบบ (pattern matching) คือการตรวจสอบลำดับของ โทเค็น ที่กำหนด ว่ามีส่วนประกอบของ รูปแบบ ใดรูปแบบหนึ่งอยู่หรือไม่ แตกต่างจาก การรู้จำรูปแบบ...
การจับคู่รูปแบบ
ในวิทยาการคอมพิวเตอร์การจับคู่รูปแบบ (pattern matching)คือการตรวจสอบลำดับของโทเค็น ที่กำหนด ว่ามีส่วนประกอบของรูปแบบ ใดรูปแบบหนึ่งอยู่หรือไม่ แตกต่างจากการรู้จำรูปแบบ (pattern recognition) ตรงที่ การจับคู่มักจะต้องตรงกันอย่างแม่นยำ: "ไม่ตรงกันก็ตรงกันไม่ตรงกัน" โดยทั่วไปแล้วรูปแบบจะมีรูปแบบเป็นลำดับหรือโครงสร้างแบบต้นไม้การใช้งานของการจับคู่รูปแบบ ได้แก่ การแสดงตำแหน่ง (ถ้ามี) ของรูปแบบภายในลำดับโทเค็น การแสดงส่วนประกอบบางอย่างของรูปแบบที่ตรงกัน และการแทนที่รูปแบบที่ตรงกันด้วยลำดับโทเค็นอื่น (เช่นการค้นหาและแทนที่ )
รูปแบบลำดับ (เช่น สตริงข้อความ) มักถูกอธิบายโดยใช้regular expression และจับคู่โดยใช้ เทคนิค ต่างๆ เช่นbacktracking
รูปแบบต้นไม้ถูกใช้ในภาษาโปรแกรม บางภาษาเป็นเครื่องมือทั่วไปในการประมวล ผลข้อมูลตามโครงสร้าง เช่นC# [ 1 ] F# [ 2 ] Haskell [ 3 ] Java [ 4 ] ML , Python [ 5 ] Racket [ 6 ] Ruby [ 7 ] Rust [ 8 ] Scala [ 9 ] Swift [ 10 ]และภาษาคณิตศาสตร์เชิงสัญลักษณ์Mathematica มีไวยากรณ์พิเศษสำหรับการแสดงรูปแบบต้นไม้และโครงสร้างภาษาสำหรับการดำเนินการตามเงื่อนไขและการดึงค่าตามรูป แบบต้นไม้
บ่อยครั้งสามารถให้รูปแบบทางเลือกที่ลองใช้ทีละแบบได้ ซึ่งทำให้เกิดโครงสร้างการเขียนโปรแกรมแบบมีเงื่อนไขที่มีประสิทธิภาพ การจับคู่รูปแบบบางครั้งรวมถึงการสนับสนุนสำหรับเงื่อนไข[ 11 ]
ประวัติศาสตร์
ภาษาโปรแกรมยุคแรกที่มีโครงสร้างการจับคู่รูปแบบ ได้แก่COMIT (1957) และSNOBOL (1962) ซึ่งนำเสนอการจับคู่รูปแบบเป็นความสามารถหลักและระดับแรกของภาษาสำหรับการจัดการสตริงและข้อความรูปแบบ นี้ พัฒนาไปสู่การประเมินข้อมูลแบบมีโครงสร้างตามต้นไม้ด้วยRefal (1968) ซึ่งใช้การจับคู่รูปแบบเพื่อจัดการนิพจน์เชิงสัญลักษณ์ แนวคิดนี้ได้รับการปรับใช้ในการเขียนโปรแกรมเชิงตรรกะด้วยProlog (1972) ซึ่งการจับคู่รูปแบบอยู่ในรูปแบบของการรวมโครงสร้างเพื่อแก้ไขคำถามเชิงตรรกะภาษาโปรแกรมเชิงฟังก์ชันได้นำคุณสมบัตินี้มาใช้และกำหนดรูปแบบอย่างเป็นทางการอย่างรวดเร็วในช่วงปลายทศวรรษ 1970 และต้นทศวรรษ 1980 โดยเริ่มจากSt Andrews Static Language (SASL) (1976), NPL (1977) และKent Recursive Calculator (KRC) (1981) [ 12 ]
คุณสมบัติการจับคู่รูปแบบของอาร์กิวเมนต์ฟังก์ชันในภาษาML (1973) และภาษาถิ่นStandard ML (1983) ได้กำหนดรูปแบบการตรวจสอบความครบถ้วนสมบูรณ์ในระหว่างการคอมไพล์อย่างเป็นทางการ แนวทางนี้ได้ถูกนำไปใช้ในภาษาการเขียนโปรแกรมเชิงฟังก์ชันอื่นๆ ที่ได้รับอิทธิพลจากภาษาเหล่านี้ เช่น Haskell (1990), Scala (2004) และF# (2005) โครงสร้างการจับคู่รูปแบบด้วยmatchคำหลักที่ถูกนำมาใช้ในภาษาถิ่นML Caml (1985) ได้ถูกนำไปใช้ในภาษาต่างๆ เช่นOCaml (1996), F# (2005), F* (2011) และRust (2015) เมื่อเวลาผ่านไป ภาษาแบบหลายพาราดิกม์เริ่มนำประเภทข้อมูลเชิงพีชคณิตและการจับคู่รูปแบบมาใช้โดยตรง ซึ่งนำไปสู่การใช้งานที่ทันสมัย เช่น ไวยากรณ์ ของ Pythonmatch-case (2021) และ การปรับปรุงการจับคู่รูปแบบ ของ Java (2023) [ 13 ]
โปรแกรมแก้ไขข้อความหลาย โปรแกรม รองรับการจับคู่รูปแบบต่างๆ เพื่ออำนวยความสะดวกในการค้นหาและแทนที่ขั้นสูงโปรแกรมแก้ไข QEDซึ่งออกแบบโดยKen Thompsonเป็นผู้บุกเบิกในการสนับสนุนการค้นหาด้วยนิพจน์ปกติ การนำการแยกวิเคราะห์นิพจน์ปกติมาใช้ในQED ของ Thompson ได้วางรากฐานสำหรับยูทิลิตี้การค้นหาข้อความในed , sedและgrep นอกจากนี้ โปรแกรมแก้ไข TECOบางเวอร์ชันยังรองรับคุณสมบัติการจับคู่ขั้นสูง รวมถึงตัวดำเนินการตรรกะ OR ในการค้นหา[ 14 ]
ระบบพีชคณิตคอมพิวเตอร์ (CAS) โดยทั่วไปสนับสนุนการจับคู่รูปแบบบนนิพจน์พีชคณิตเพื่อให้ได้การลดรูปเชิงสัญลักษณ์และการบูรณาการ ระบบในยุคแรกๆ เช่นMacsyma (1968) ใช้การจับคู่รูปแบบเชิงความหมายเพื่อรับรู้ความเท่าเทียมกันทางพีชคณิตตัวอย่างเช่น กลไกภายในของมันสามารถจับคู่ทั้งและ ได้สำเร็จ ในฐานะการเกิดขึ้นของแม่แบบรูปแบบ "กำลังสองใน x" ระบบพีชคณิตคอมพิวเตอร์สมัยใหม่ รวมถึงMathematicaและMapleอาศัยกฎการจับคู่รูปแบบอย่างมากในการแปลงนิพจน์ของผู้ใช้ ค้นหาคำตอบเชิงวิเคราะห์สำหรับสมการเชิงอนุพันธ์และสร้างกรอบการลดรูปที่ผู้ใช้กำหนด[ 15 ]3x2 + 4(x + 1)(x + 6)
ศัพท์เฉพาะ
การจับคู่รูปแบบเกี่ยวข้องกับศัพท์เฉพาะทาง
- การจับคู่
- การกระทำที่เปรียบเทียบสิ่งที่กำลังตรวจสอบกับรูปแบบ (หรือชุดรูปแบบ) โดยอาจเลือกส่วนที่ต่อเนื่องดึงส่วนที่เชื่อมโยง ออกมา ทำการแทนที่หรือการผสมผสานของสิ่งเหล่านี้ เรียกอีกอย่างว่าการแยกโครงสร้าง (destructuring )
- ลวดลาย
- ไวยากรณ์ที่อธิบายโครงสร้างที่คาดหวังในสิ่งที่ตรวจสอบรวมถึงการระบุส่วนต่างๆ ของสิ่งที่ตรวจสอบที่จะดึงออกมา ( การผูกค่า ) หรือละเว้น ( สัญลักษณ์ตัวแทน ) ภาษาของรูปแบบอาจมีความหลากหลาย โปรดดูคำศัพท์ที่ใช้ระบุรูปแบบเฉพาะประเภทต่างๆ ด้านล่าง
- ผู้ถูกตรวจสอบ
- ค่าที่จะตรวจสอบและเปรียบเทียบกับรูปแบบ ในกรณีส่วนใหญ่ ค่านี้จะเป็นโครงสร้างข้อมูลชนิดใดชนิดหนึ่ง โดยมีประเภทเป็นคู่ตรงข้ามกับรูปแบบที่นำมาใช้ เรียกอีกอย่างว่าค่าเป้าหมายหรือตัวแยกแยะ
- ต่อเนื่อง
- ในบางภาษา เมื่อมีการใช้รูปแบบทางเลือกหลายรูปแบบกับสิ่งที่ถูกตรวจสอบ เมื่อมีรูปแบบทางเลือกหนึ่งที่ตรงกัน โค้ดส่วนที่เกี่ยวข้องจะถูกเรียกใช้ในสภาพแวดล้อมที่ขยายด้วยการผูกมัด ของรูปแบบที่ตรงกันนั้น โค้ดส่วนนี้คือส่วนต่อขยายที่เชื่อมโยงกับรูปแบบนั้น
- การทดแทน
- การแทนที่ส่วนหนึ่งของโครงสร้างข้อมูลเป้าหมายด้วยค่าที่คำนวณได้ การคำนวณอาจขึ้นอยู่กับส่วนที่ถูกแทนที่ของข้อมูลเป้าหมาย รวมถึงการเชื่อมโยงอื่นๆ ที่ดึงมาจากข้อมูลเป้าหมายด้วย
ศัพท์เฉพาะของรูปแบบ
แม้ว่าแนวคิดบางอย่างจะค่อนข้างพบได้ทั่วไปในภาษาแพทเทิร์นหลายภาษา แต่ภาษาแพทเทิร์นบางภาษาก็มีส่วนขยายที่เป็นเอกลักษณ์หรือแปลกใหม่
- ผูกพัน
- วิธีการเชื่อมโยงชื่อกับส่วนหนึ่งของสิ่งที่ถูกตรวจสอบ เพื่อให้ชื่อนั้นผูกติดอยู่กับส่วนนั้นเมื่อการดำเนินการต่อเนื่องทำงาน ตัวอย่างเช่น ใน Rust คาดว่าจะเป็นคู่ และและเป็นการผูกที่นำตัวแปรที่มีชื่อเดียวกันเข้ามาอยู่ในขอบเขตของการดำเนินการต่อเนื่อง (" ")
matchv{(a,b)=>...}vab...
- ไวลด์การ์ด
- รูปแบบไวด์การ์ด (wildcard) ซึ่งมักเขียนด้วยเครื่องหมายขีดล่างตัวเดียว
_จะยอมรับค่าทั้งหมดโดยไม่ต้องตรวจสอบเพิ่มเติม และไม่สนใจโครงสร้างของค่าเหล่านั้น เรียกอีกอย่างว่า รูปแบบการทิ้ง (discard) , รูปแบบไวด์ (wild pattern) , รูปแบบจับทั้งหมด (catch-all pattern ) หรือ ช่องว่าง ( hole )
- อารักขา
- เงื่อนไข ( Guard)คือนิพจน์ที่ต้องสำเร็จ (หรือให้ค่าบูลีนเป็นจริง) ในขั้นตอนสุดท้ายก่อนที่จะพิจารณาว่ารูปแบบนั้นตรงกันอย่างสมบูรณ์ ในบางภาษา (เช่นErlang ) เงื่อนไขจะเขียนโดยใช้ส่วนย่อยที่จำกัดของภาษาทั้งหมด ในขณะที่บางภาษา (เช่นHaskell ) เงื่อนไขอาจใช้ภาษาทั้งหมด
- ภาคแสดง
- ภาษารูปแบบบางภาษาอนุญาตให้ฝังฟังก์ชัน เงื่อนไขที่ผู้ใช้กำหนดเองลงในรูปแบบได้ เงื่อนไขนั้นจะถูกนำไปใช้กับส่วนของสิ่งที่ตรวจสอบซึ่งสอดคล้องกับตำแหน่งของเงื่อนไขในรูปแบบ หากเงื่อนไขตอบกลับด้วยค่าบูลีนเท็จ รูปแบบนั้นจะถือว่าล้มเหลว ตัวอย่างเช่น ในภาษา Racket รูปแบบจะคาดหวังรายการก่อน จากนั้นจึงนำเงื่อนไขไปใช้กับแต่ละองค์ประกอบ ดังนั้นรูปแบบโดยรวมจะสำเร็จก็ต่อเมื่อสิ่งที่ตรวจสอบเป็นรายการของตัวเลขคู่เท่านั้น
(list(?even?)...)even?
- รูปแบบการดู
- ภาษาต่างๆ เช่น Haskell [ 16 ]และ Racket [ 17 ]มีรูปแบบมุมมอง (view patterns ) ซึ่งฟังก์ชันที่ผู้ใช้กำหนดจะแปลงส่วนของสิ่งที่ตรวจสอบที่สอดคล้องกับตำแหน่งของรูปแบบมุมมองก่อนที่จะดำเนินการจับคู่ต่อไป รูปแบบมุมมองจะขยายรูปแบบภาคแสดง (predicate patterns) ทำให้สามารถจับคู่เพิ่มเติมกับผลลัพธ์ของฟังก์ชันได้ แทนที่จะคาดหวังเพียงค่าบูลีน
- ข้อจำกัด
- ภาษารูปแบบบางภาษาอนุญาตให้เปรียบเทียบส่วนต่างๆ ของสิ่งที่ตรวจสอบกับโครงสร้างข้อมูลที่คำนวณไว้ก่อนหน้านี้ (หรือค่าคงที่) ได้โดยตรง ตัวอย่างเช่น รูปแบบใน Racket จะเปรียบเทียบค่ากับผลลัพธ์ของการประเมินค่าใน Erlang การกล่าวถึงตัวแปรใดๆ ที่อยู่ในขอบเขตของรูปแบบอยู่แล้วจะทำให้ตัวแปรนั้นทำหน้าที่เป็นข้อจำกัดในลักษณะนี้ (แทนที่จะเป็นการผูกมัด)
(==expr)expr
- รูปแบบตามตัวอักษร; รูปแบบอะตอม
- รูปแบบที่ตรงกับข้อมูลอะตอมิกอย่างง่าย เช่น
123หรือ"hello"เรียกว่ารูปแบบตัวอักษร (literal patterns )
- รูปแบบผสม
- รูปแบบที่แยกโครงสร้างค่าผสม เช่น รายการ ตารางแฮช ทูเพิล โครงสร้าง หรือเรคอร์ด โดยมีรูปแบบย่อยสำหรับแต่ละค่าที่ประกอบขึ้นเป็นโครงสร้างข้อมูลผสมนั้น เรียกว่า รูป แบบผสม
- ทางเลือก (
or-รูปแบบ) - ภาษาโปรแกรมหลายภาษาอนุญาตให้มีทางเลือกหลายทางในระดับบนสุดของโครงสร้างการจับคู่รูปแบบ โดยแต่ละทางเลือกจะเชื่อมโยงกับการดำเนินการต่อเนื่องบางภาษายังอนุญาตให้มีทางเลือกภายในรูปแบบเดียวกัน ในกรณีส่วนใหญ่ ทางเลือกเหล่านั้นจะมีข้อจำกัดเพิ่มเติม เช่น ทางเลือกทุกทางอาจต้องสร้างชุดการผูกข้อมูล ชุดเดียวกัน (ในประเภทเดียวกัน)
- มาโคร
- บางภาษาอนุญาตให้ใช้มาโครในบริบทของรูปแบบเพื่ออนุญาตให้มีการสรุปแบบนามธรรมเหนือรูปแบบ ตัวอย่างเช่น ใน Racket ตัวขยายการจับคู่ทำหน้าที่นี้[ 18 ]
ประเภท
รูปแบบดั้งเดิม
รูปแบบที่ง่ายที่สุดในการจับคู่รูปแบบคือค่าที่ระบุอย่างชัดเจนหรือตัวแปร ตัวอย่างเช่น ลองพิจารณาการนิยามฟังก์ชันอย่างง่ายในไวยากรณ์ Haskell (พารามิเตอร์ของฟังก์ชันไม่ได้อยู่ในวงเล็บ แต่คั่นด้วยช่องว่าง เครื่องหมาย = ไม่ใช่การกำหนดค่า แต่เป็นการกำหนด):
f 0 = 1ในที่นี้ 0 คือรูปแบบค่าเดียว เมื่อใดก็ตามที่ฟังก์ชัน f ได้รับค่า 0 เป็นอาร์กิวเมนต์ รูปแบบจะตรงกันและฟังก์ชันจะส่งคืนค่า 1 แต่ถ้าเป็นอาร์กิวเมนต์อื่น การจับคู่และฟังก์ชันจะล้มเหลว เนื่องจากไวยากรณ์รองรับรูปแบบทางเลือกในการกำหนดฟังก์ชัน เราจึงสามารถขยายการกำหนดฟังก์ชันให้รับอาร์กิวเมนต์ทั่วไปได้มากขึ้น:
f n = n * f ( n - 1 )ในที่นี้ รูปแบบแรกnคือรูปแบบตัวแปรเดียว ซึ่งจะตรงกับอาร์กิวเมนต์ใดๆ ก็ได้ และผูกอาร์กิวเมนต์นั้นเข้ากับชื่อ n เพื่อใช้ในส่วนที่เหลือของคำนิยาม ใน Haskell (ซึ่งแตกต่างจากHope อย่างน้อย ) รูปแบบจะถูกลองใช้ตามลำดับ ดังนั้นคำนิยามแรกจึงยังคงใช้ได้ในกรณีเฉพาะที่อินพุตเป็น 0 ในขณะที่สำหรับอาร์กิวเมนต์อื่นๆ ฟังก์ชันจะส่งคืนค่าn * f (n-1)โดยมี n เป็นอาร์กิวเมนต์
รูปแบบไวด์การ์ด (มักเขียนเป็น_) ก็เรียบง่ายเช่นกัน: เหมือนกับชื่อตัวแปร มันตรงกับค่าใดๆ ก็ได้ แต่ไม่ได้ผูกค่ากับชื่อใดๆ อัลกอริทึมสำหรับการจับคู่ไวด์การ์ดในสถานการณ์การจับคู่สตริงแบบง่ายๆ ได้รับการพัฒนาในรูปแบบเรียกซ้ำและไม่เรียกซ้ำหลายรูปแบบ[ 19 ]
ลวดลายต้นไม้
สามารถสร้างรูปแบบที่ซับซ้อนมากขึ้นได้จากรูปแบบดั้งเดิมในส่วนก่อนหน้า โดยปกติแล้วจะทำในลักษณะเดียวกับการสร้างค่าโดยการรวมค่าอื่นๆ เข้าด้วยกัน ความแตกต่างก็คือ เมื่อมีส่วนประกอบที่เป็นตัวแปรและสัญลักษณ์ตัวแทน รูปแบบจะไม่ถูกสร้างขึ้นเป็นค่าเดียว แต่จะจับคู่กับกลุ่มของค่าที่เป็นการรวมกันขององค์ประกอบที่เป็นรูปธรรมและองค์ประกอบที่สามารถเปลี่ยนแปลงได้ภายในโครงสร้างของรูปแบบ
รูปแบบต้นไม้ (Tree pattern) อธิบายส่วนหนึ่งของต้นไม้โดยเริ่มต้นจากโหนดหนึ่ง แล้วระบุสาขาและโหนดบางส่วน และเว้นบางส่วนไว้โดยไม่ระบุด้วยตัวแปรหรือรูปแบบตัวแทน (wildcard pattern) อาจจะช่วยให้เข้าใจได้ง่ายขึ้นหากนึกถึงโครงสร้างต้นไม้ไวยากรณ์นามธรรม (Abstract Syntax Tree)ของภาษาโปรแกรมและชนิดข้อมูลเชิงพีชคณิต
ฮัสเคลล์
ในภาษา Haskell บรรทัดต่อไปนี้กำหนดชนิดข้อมูลเชิงพีชคณิตColorที่มีตัวสร้างข้อมูลเพียงตัวเดียวColorConstructorซึ่งห่อหุ้มจำนวนเต็มและสตริงไว้
ข้อมูลสี= ตัวสร้างสีจำนวนเต็มสตริงตัวสร้าง (constructor) เป็นโหนดในโครงสร้างต้นไม้ และจำนวนเต็มและสตริงเป็นใบในกิ่งก้านของโครงสร้างนั้น
เมื่อเราต้องการเขียนฟังก์ชันเพื่อสร้างColorชนิดข้อมูลนามธรรมเราต้องการเขียนฟังก์ชันเพื่อเชื่อมต่อกับชนิดข้อมูลนั้น และด้วยเหตุนี้เราจึงต้องการดึงข้อมูลบางส่วนจากชนิดข้อมูลนั้น ตัวอย่างเช่น เฉพาะสตริงหรือเฉพาะส่วนที่เป็นจำนวนเต็มของColorข้อมูล
ถ้าเราส่งตัวแปรที่มีชนิดข้อมูลเป็นสี (Color) เข้าไป เราจะดึงข้อมูลจากตัวแปรนี้ได้อย่างไร ตัวอย่างเช่น สำหรับฟังก์ชันที่ใช้ดึงค่าจำนวนเต็มของColorสี เราสามารถใช้รูปแบบโครงสร้างแบบต้นไม้ (tree pattern) อย่างง่ายๆ และเขียนได้ดังนี้:
integerPart ( ColorConstructor theInteger _ ) = theIntegerเช่นกัน:
stringPart ( ColorConstructor _ theString ) = theStringการสร้างฟังก์ชันเหล่านี้สามารถทำได้โดยอัตโนมัติโดยใช้ไวยากรณ์ ระเบียน ข้อมูลของ Haskell
โอแคมล์
ตัวอย่าง OCamlนี้ซึ่งกำหนดโครงสร้างต้นไม้แดง-ดำและฟังก์ชันสำหรับปรับสมดุลใหม่หลังจากแทรกองค์ประกอบ แสดงให้เห็นถึงวิธีการจับคู่บนโครงสร้างที่ซับซ้อนมากขึ้นซึ่งสร้างขึ้นโดยชนิดข้อมูลแบบเรียกซ้ำ คอมไพเลอร์จะตรวจสอบในระหว่างการคอมไพล์ว่ารายการกรณีต่างๆ นั้นครบถ้วนและไม่มีกรณีที่ซ้ำซ้อน
ประเภทสี= แดง| ดำประเภท' ต้นไม้= ว่างเปล่า| ต้นไม้สี* ' ต้นไม้* ' a * ' ต้นไม้ให้rebalance t = match t with | Tree ( Black , Tree ( Red , Tree ( Red , a , x , b ), y , c ), z , d ) | Tree ( Black , Tree ( Red , a , x , Tree ( Red , b , y , c )), z , d ) | Tree ( Black , a , x , Tree ( Red , Tree ( Red , b , y , c ), z , d )) | Tree ( Black , a , x , Tree ( Red , b , y , Tree ( Red , c , z , d ))) -> Tree ( Red , Tree ( Black , a , x , b ), y , Tree ( Black , c , z , d )) | _ -> t (* กรณี 'จับทั้งหมด' หากไม่มีรูปแบบก่อนหน้าตรงกัน *)การใช้งาน
การกรองข้อมูลด้วยรูปแบบ
การจับคู่รูปแบบสามารถใช้เพื่อกรองข้อมูลที่มีโครงสร้างเฉพาะได้ ตัวอย่างเช่น ในภาษา Haskell เราสามารถใช้ list comprehension ในการกรองข้อมูลประเภทนี้ได้:
[ A x | A x <- [ A 1 , B 1 , A 2 , B 2 ]]ประเมินเป็น
[A 1, A 2]
การจับคู่รูปแบบใน Mathematica
ในMathematicaโครงสร้างเดียวที่มีอยู่คือต้นไม้ซึ่งเต็มไปด้วยสัญลักษณ์ ใน ไวยากรณ์ Haskellที่ใช้มาจนถึงปัจจุบัน สามารถนิยามได้ดังนี้
ข้อมูลSymbolTree = Symbol String [ SymbolTree ]ตัวอย่างแผนผังต้นไม้ อาจมีลักษณะดังนี้
สัญลักษณ์"a" [ สัญลักษณ์"b" [], สัญลักษณ์"c" []]ในไวยากรณ์แบบดั้งเดิมที่เหมาะสมกว่า สัญลักษณ์จะถูกเขียนตามที่เป็นอยู่ และระดับของต้นไม้จะถูกแทนด้วย[]ดังนั้น ตัวอย่างเช่น จึงa[b,c]เป็นต้นไม้ที่มี a เป็นโหนดแม่ และ b กับ c เป็นโหนดลูก
รูปแบบใน Mathematica เกี่ยวข้องกับการใส่เครื่องหมาย "_" ในตำแหน่งต่างๆ ในโครงสร้างต้นไม้ ตัวอย่างเช่น รูปแบบ
เอ[_]
จะจับคู่องค์ประกอบต่างๆ เช่น A[1], A[2] หรือโดยทั่วไปคือ A[ x ] โดยที่xคือเอนทิตีใดๆ ในกรณีนี้Aคือองค์ประกอบที่เป็นรูปธรรม ในขณะที่_แสดงถึงส่วนของต้นไม้ที่สามารถเปลี่ยนแปลงได้ สัญลักษณ์ที่นำหน้า จะ_ผูกการจับคู่กับชื่อตัวแปรนั้น ในขณะที่สัญลักษณ์ที่ต่อท้าย จะ จำกัดการจับคู่เฉพาะโหนดของสัญลักษณ์นั้น โปรดทราบว่าแม้แต่ช่องว่างเอง ก็ _ถูกแทนด้วยBlank[]สำหรับ_และBlank[x]สำหรับ_x
ฟังก์ชัน Mathematica Casesจะกรององค์ประกอบของอาร์กิวเมนต์แรกที่ตรงกับรูปแบบในอาร์กิวเมนต์ที่สอง: [ 20 ]
กรณี[{ a [ 1 ], b [ 1 ], a [ 2 ], b [ 2 ]}, a [ _ ] ]ประเมินเป็น
{ a [ 1 ], a [ 2 ]}การจับคู่รูปแบบใช้กับโครงสร้างของนิพจน์ ในตัวอย่างด้านล่างนี้
กรณี[ { a [ b ], a [ b , c ], a [ b [ c ], d ], a [ b [ c ], d [ e ]], a [ b [ c ], d , e ]}, a [ b [ _ ], _ ] ]ส่งคืน
{ a [ b [ c ], d ], a [ b [ c ], d [ e ]]}เนื่องจากมีเพียงองค์ประกอบเหล่านี้เท่านั้นที่จะตรงกับรูปแบบa[b[_],_]ข้างต้น
ใน Mathematica ยังสามารถดึงโครงสร้างที่เกิดขึ้นระหว่างการคำนวณได้ ไม่ว่าโครงสร้างเหล่านั้นจะปรากฏขึ้นอย่างไรหรือที่ใดก็ตาม ฟังก์ชันนี้Traceสามารถใช้ตรวจสอบการคำนวณและส่งคืนองค์ประกอบที่เกิดขึ้นซึ่งตรงกับรูปแบบ ตัวอย่างเช่น เราสามารถกำหนดลำดับฟิโบนาชชีได้ดังนี้
ปลิ้นปล้อน[ 0 | 1 ] := 1 ตอแหล[ n_ ] := ตอแหล[ n -1 ] + ตอแหล[ n -2 ]จากนั้น เราสามารถถามคำถามได้ว่า: เมื่อกำหนด fib[3] แล้ว ลำดับของการเรียก Fibonacci แบบเรียกซ้ำคืออะไร?
ติดตาม[ fib [ 3 ], fib [ _ ]]ส่งคืนโครงสร้างที่แสดงถึงการเกิดขึ้นของรูปแบบfib[_]ในโครงสร้างการคำนวณ:
{ ตอแหล[ 3 ],{ ตอแหล[ 2 ],{ ตอแหล[ 1 ]},{ ตอแหล[ 0 ]}},{ ตอแหล[ 1 ]}}การเขียนโปรแกรมเชิงประกาศ
ในภาษาการเขียนโปรแกรมเชิงสัญลักษณ์ การใช้รูปแบบเป็นอาร์กิวเมนต์ของฟังก์ชันหรือเป็นองค์ประกอบของโครงสร้างข้อมูลนั้นทำได้ง่าย ผลที่ตามมาคือความสามารถในการใช้รูปแบบเพื่อกำหนดข้อความเกี่ยวกับข้อมูลต่างๆ อย่างชัดเจน และเพื่อสั่งการฟังก์ชันให้ทำงานได้อย่างยืดหยุ่น
ตัวอย่างเช่นฟังก์ชัน ของ MathematicaCompileสามารถใช้เพื่อสร้างโค้ดเวอร์ชันที่มีประสิทธิภาพมากขึ้นได้ ในตัวอย่างต่อไปนี้ รายละเอียดไม่สำคัญมากนัก สิ่งสำคัญคือส่วนย่อยของนิพจน์นั้น{{com[_], Integer}}ระบุCompileว่านิพจน์ในรูปแบบดังกล่าวcom[_]สามารถถือว่าเป็นจำนวนเต็มได้เพื่อวัตถุประสงค์ในการคอมไพล์:
com [ i_ ] := Binomial [ 2 i , i ] Compile [{ x , { i , _Integer }}, x ^ com [ i ], {{ com [ _ ], Integer }}]กล่องจดหมายในErlangก็ทำงานในลักษณะนี้เช่นกัน
ความสัมพันธ์ แบบCurry–Howardระหว่างบทพิสูจน์และโปรแกรมเชื่อมโยงการจับคู่รูปแบบสไตล์ML เข้ากับ การวิเคราะห์กรณีและการพิสูจน์โดยการครอบคลุมทุกกรณี
การจับคู่รูปแบบและสตริง
รูปแบบการจับคู่รูปแบบที่พบได้บ่อยที่สุดคือการจับคู่กับสตริงของตัวอักษร ในภาษาโปรแกรมหลายภาษา จะมีการใช้ไวยากรณ์เฉพาะของสตริงเพื่อแสดงนิพจน์ปกติ ซึ่งเป็นรูปแบบที่อธิบายตัวอักษรในสตริง
อย่างไรก็ตาม เป็นไปได้ที่จะทำการจับคู่รูปแบบสตริงบางอย่างภายในกรอบการทำงานเดียวกันกับที่ได้กล่าวถึงในบทความนี้
รูปแบบต้นไม้สำหรับสตริง
ใน Mathematica สตริงจะถูกแสดงเป็นโครงสร้างต้นไม้ โดยมีรากเป็น StringExpression และอักขระทั้งหมดเรียงตามลำดับเป็นลูกของราก ดังนั้น ในการจับคู่ "อักขระต่อท้ายจำนวนเท่าใดก็ได้" จึงต้องใช้สัญลักษณ์ตัวแทนใหม่ ___ ซึ่งแตกต่างจาก _ ที่จะจับคู่ได้เฉพาะอักขระตัวเดียวเท่านั้น
ในภาษา Haskell และ ภาษา การเขียนโปรแกรมเชิงฟังก์ชันโดยทั่วไป สตริงจะถูกแทนด้วยลิสต์ เชิงฟังก์ชัน ของอักขระ ลิสต์เชิงฟังก์ชันถูกกำหนดให้เป็นลิสต์ว่าง หรือองค์ประกอบที่สร้างขึ้นจากลิสต์ที่มีอยู่แล้ว ในไวยากรณ์ของ Haskell:
[] -- รายการว่างx : xs -- องค์ประกอบ x ที่สร้างขึ้นจากรายการ xsโครงสร้างของลิสต์ที่มีองค์ประกอบบางอย่างจึงเป็นดังนี้element:listเมื่อทำการจับคู่รูปแบบ เราจะยืนยันว่าข้อมูลบางส่วนเท่ากับรูปแบบที่กำหนดไว้ ตัวอย่างเช่น ในฟังก์ชัน:
ส่วนหัว( องค์ประกอบ: รายการ) = องค์ประกอบเรายืนยันว่าองค์ประกอบแรกของ อาร์กิวเมนต์ของ headฟังก์ชันเรียกว่า element และฟังก์ชันจะส่งคืนค่านี้ เรารู้ว่านี่คือองค์ประกอบแรกเนื่องจากวิธีการกำหนดลิสต์ ซึ่งก็คือการสร้างองค์ประกอบเดียวลงในลิสต์ องค์ประกอบเดียวนี้จะต้องเป็นองค์ประกอบแรก ลิสต์ว่างจะไม่ตรงกับรูปแบบเลย เพราะลิสต์ว่างไม่มีส่วนหัว (องค์ประกอบแรกที่ถูกสร้างขึ้น)
ในตัวอย่างนี้ เราไม่จำเป็นต้องใช้listดังนั้นเราจึงสามารถละเลยมันได้ และเขียนฟังก์ชันได้ดังนี้:
ส่วนหัว( องค์ประกอบ: _ ) = องค์ประกอบการแปลง Mathematica ที่เทียบเท่ากันแสดงได้ดังนี้
ส่วนหัว[องค์ประกอบ, ]:=องค์ประกอบ
ตัวอย่างรูปแบบสตริง
ตัวอย่างเช่น ในโปรแกรม Mathematica
นิพจน์สตริง[ "a" , _ ]จะตรงกับสตริงที่มีอักขระสองตัวและขึ้นต้นด้วย "a"
รูปแบบเดียวกันนี้ในภาษา Haskell:
[ 'a' , _ ]สามารถนำเอนทิตีเชิงสัญลักษณ์มาใช้แทนคุณลักษณะที่เกี่ยวข้องหลายประเภทของสตริงได้ ตัวอย่างเช่น
นิพจน์สตริง[ตัวอักษร, ตัวเลข]
จะตรงกับสตริงที่ประกอบด้วยตัวอักษรนำหน้า ตามด้วยตัวเลข
ในภาษา Haskell สามารถใช้ การ์ด เพื่อสร้างการจับคู่แบบเดียวกันได้:
[ ตัวอักษร, ตัวเลข] | เป็นตัวอักษรและตัวเลขข้อได้เปรียบหลักของการจัดการสตริงเชิงสัญลักษณ์คือ สามารถบูรณาการเข้ากับส่วนอื่นๆ ของภาษาโปรแกรมได้อย่างสมบูรณ์ แทนที่จะเป็นหน่วยย่อยที่แยกต่างหากเพื่อวัตถุประสงค์เฉพาะ สามารถใช้พลังทั้งหมดของภาษาเพื่อสร้างรูปแบบต่างๆ หรือวิเคราะห์และแปลงโปรแกรมที่มีรูปแบบเหล่านั้นได้
สโนโบล
SNOBOL ( String Oriented and symBOlic Language ) เป็นภาษาโปรแกรมคอมพิวเตอร์ที่พัฒนาขึ้นระหว่างปี 1962 ถึง 1967 ที่ ห้องปฏิบัติการ AT&T BellโดยDavid J. Farber , Ralph E. Griswoldและ Ivan P. Polonsky
SNOBOL4 แตกต่างจากภาษาโปรแกรมส่วนใหญ่ตรงที่รูปแบบ (pattern) เป็นชนิดข้อมูลระดับแรก ( กล่าวคือชนิดข้อมูลที่สามารถจัดการค่าได้ทุกวิธีที่อนุญาตสำหรับชนิดข้อมูลอื่น ๆ ในภาษาโปรแกรม) และมีตัวดำเนินการสำหรับการเชื่อมต่อและการสลับ รูปแบบ สตริงที่สร้างขึ้นระหว่างการทำงานสามารถถือได้ว่าเป็นโปรแกรมและเรียกใช้งานได้
SNOBOL เป็นภาษาที่ใช้สอนกันอย่างแพร่หลายในมหาวิทยาลัยขนาดใหญ่ของสหรัฐอเมริกาในช่วงปลายทศวรรษ 1960 และต้นทศวรรษ 1970 และถูกนำมาใช้กันอย่างแพร่หลายในทศวรรษ 1970 และ 1980 ในฐานะภาษาสำหรับการจัดการข้อความในสาขา มนุษยศาสตร์
นับตั้งแต่การสร้าง SNOBOL ภาษาใหม่ๆ เช่นAWKและPerlได้ทำให้การจัดการสตริงโดยใช้regular expressionเป็นที่นิยม อย่างไรก็ตาม รูปแบบ SNOBOL4 ครอบคลุม ไวยากรณ์ Backus–Naur form (BNF) ซึ่งเทียบเท่ากับไวยากรณ์แบบไร้บริบทและมีประสิทธิภาพมากกว่าregular expression [ 21 ]
ดูเพิ่มเติม
- ภาษามาร์กอัปปัญญาประดิษฐ์ (AIML) สำหรับภาษา AI ที่ใช้การจับคู่รูปแบบในคำพูด
- ภาษาAWK
- รูปแบบ Coccinelleตรงกับซอร์สโค้ด C
- การจับคู่ไวด์การ์ด
- glob (การเขียนโปรแกรม)
- แคลคูลัสรูปแบบ
- การรู้จำรูปแบบสำหรับรูปแบบคลุมเครือ
- PCRE ( Perl Compatible Regular Expressions) คือการใช้งานการจับคู่รูปแบบสตริงที่ทันสมัยและเป็นที่นิยม ซึ่งสามารถนำไปปรับใช้ได้ในหลายภาษา
- REBOLใช้การแยกวิเคราะห์แบบแผนสำหรับการจับคู่รูปแบบเพื่อสร้างภาษาถิ่น
- การบูรณาการเชิงสัญลักษณ์
- สหภาพที่ถูกแท็ก
- ทอม (ภาษาการจับคู่รูปแบบ)
- SNOBOLเป็นภาษาโปรแกรมที่ใช้การจับคู่รูปแบบประเภทหนึ่ง
- ภาษารูปแบบ — เป็นเชิงเปรียบเทียบ ดึงมาจากสถาปัตยกรรม
- การจับคู่กราฟ
- การจับคู่รูปแบบสองมิติ
ลิงก์ภายนอก
- มุมมอง: ส่วนขยายสำหรับการจับคู่รูปแบบใน Haskell
- Nikolaas N. Oosterhof, Philip KF Hölzenspies และ Jan Kuper. รูปแบบการประยุกต์ใช้ . การนำเสนอในงานประชุม Trends in Functional Programming, 2005
- JMatch : ภาษา Javaที่เพิ่มฟังก์ชันการจับคู่รูปแบบ
- ShowTrend : การจับคู่รูปแบบออนไลน์สำหรับราคาหุ้น
- ประวัติที่ไม่สมบูรณ์ของโปรแกรมแก้ไขข้อความ QEDโดยเดนนิส ริทชี - นำเสนอประวัติของนิพจน์ปกติในโปรแกรมคอมพิวเตอร์
- หนังสือ "การนำภาษาการเขียนโปรแกรมเชิงฟังก์ชันไปใช้" หน้า 53–103โดย Simon Peyton Jones จัดพิมพ์โดย Prentice Hall ปี 1987
- เนเมอร์เล่, การจับคู่รูปแบบ
- Erlang, การจับคู่รูปแบบ
- Prop: ภาษาจับคู่รูปแบบที่ใช้ C++, ปี 1999
- PatMat: ไลบรารีการจับคู่รูปแบบในภาษา C++ ที่พัฒนาบนพื้นฐานของSNOBOL / SPITBOL
- Temur Kutsia. Flat Matching . Journal of Symbolic Computation 43(12): 858–873. อธิบายรายละเอียดเกี่ยวกับ flat matching ใน Mathematica
- EasyPattern ภาษาสำหรับการจับคู่รูปแบบ สำหรับผู้ที่ไม่ใช่โปรแกรมเมอร์
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ การจับคู่รูปแบบ
ใน วิทยาการคอมพิวเตอร์ การ จับคู่รูปแบบ (pattern matching) คือการตรวจสอบลำดับของ โทเค็น ที่กำหนด ว่ามีส่วนประกอบของ รูปแบบ ใดรูปแบบหนึ่งอยู่หรือไม่ แตกต่างจาก การรู้จำรูปแบบ...
ประวัติศาสตร์
ภาษาโปรแกรมยุคแรกที่มีโครงสร้างการจับคู่รูปแบบ ได้แก่ COMIT (1957) และ SNOBOL (1962) ซึ่งนำเสนอการจับคู่รูปแบบเป็นความสามารถหลักและระดับแรกของภาษาสำหรับการจัดการสตริงและข้อความ รูปแบบ นี้ พัฒนาไปสู่การประเมินข้อมูลแบบมีโครงสร้างตามต้นไม้ด้วย Refal (1968)...
ศัพท์เฉพาะ
การจับคู่รูปแบบเกี่ยวข้องกับศัพท์เฉพาะทาง
ศัพท์เฉพาะของรูปแบบ
แม้ว่าแนวคิดบางอย่างจะค่อนข้างพบได้ทั่วไปในภาษาแพทเทิร์นหลายภาษา แต่ภาษาแพทเทิร์นบางภาษาก็มีส่วนขยายที่เป็นเอกลักษณ์หรือแปลกใหม่