กลับไปหน้าบทความ

อ่าน 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 ]

ดูเพิ่มเติม

  • มุมมอง: ส่วนขยายสำหรับการจับคู่รูปแบบใน 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 ภาษาสำหรับการจับคู่รูปแบบ สำหรับผู้ที่ไม่ใช่โปรแกรมเมอร์
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Pattern_matching&oldid=1360716608 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ การจับคู่รูปแบบ

ใน วิทยาการคอมพิวเตอร์ การ จับคู่รูปแบบ (pattern matching) คือการตรวจสอบลำดับของ โทเค็น ที่กำหนด ว่ามีส่วนประกอบของ รูปแบบ ใดรูปแบบหนึ่งอยู่หรือไม่ แตกต่างจาก การรู้จำรูปแบบ...

ประวัติศาสตร์

ภาษาโปรแกรมยุคแรกที่มีโครงสร้างการจับคู่รูปแบบ ได้แก่ COMIT (1957) และ SNOBOL (1962) ซึ่งนำเสนอการจับคู่รูปแบบเป็นความสามารถหลักและระดับแรกของภาษาสำหรับการจัดการสตริงและข้อความ รูปแบบ นี้ พัฒนาไปสู่การประเมินข้อมูลแบบมีโครงสร้างตามต้นไม้ด้วย Refal (1968)...

ศัพท์เฉพาะ

การจับคู่รูปแบบเกี่ยวข้องกับศัพท์เฉพาะทาง

ศัพท์เฉพาะของรูปแบบ

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