นิพจน์ทั่วไปทำงานอย่างไร


30

สมมติว่าคุณมีเอกสารที่เขียนเรียงความ คุณต้องการแยกวิเคราะห์บทความนี้เพื่อเลือกคำบางคำเท่านั้น เย็น.

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


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

3
ดังนั้นสมมติฐาน ถ้าฉันมีหลักฐานจะไม่เป็นหนึ่งใช่มั้ย
lazeR

4
นั่นไม่ใช่ประเด็น. ประเด็นคือสิ่งที่นำคุณไปสู่ข้อสันนิษฐานนั้น ... คุณไม่จำเป็นต้องมีหลักฐานสำหรับคำถามของคุณ แต่คุณจำเป็นต้องให้เหตุผลสำหรับข้อสันนิษฐานของคุณ
yannis

1
เอ่อไม่ใช่ว่าทุกตัวละครของสายป้อนเพียงแค่ย้ายเครื่องรัฐไปยังสถานะต่อไป ฉันไม่เห็นว่าใครจะทำให้การทำงานช้าลงได้
บ้าง

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

คำตอบ:


47

มันทำงานยังไง?

ดูทฤษฎีออโตมาตะ

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

อย่างไรก็ตามภาษาการเขียนโปรแกรมที่ทันสมัยที่สุด (Perl, Python, Ruby, Java (และภาษาที่ใช้ JVM), C #) ไม่ได้ใช้วิธีการนี้ พวกเขาใช้วิธีการย้อนรอยซ้ำซึ่งรวบรวมการแสดงออกปกติลงในต้นไม้หรือลำดับของการสร้างที่เป็นตัวแทนของชิ้นย่อยต่างๆของการแสดงออกปกติ ไวยากรณ์ "นิพจน์ทั่วไป" ที่ทันสมัยส่วนใหญ่นำเสนอการอ้างอิงย้อนกลับซึ่งอยู่นอกกลุ่มของภาษาปกติ (ไม่มีการแสดงแทนในขอบเขตออโตมาตะ) ซึ่งสามารถนำไปใช้งานได้เล็กน้อยในแนวทางย้อนรอยแบบวนซ้ำ

การปรับให้เหมาะสมมักจะให้เครื่องสถานะที่มีประสิทธิภาพมากขึ้น ตัวอย่างเช่นพิจารณา aaaab | aaaac | aaaad โปรแกรมเมอร์ทั่วไปสามารถใช้งานการค้นหาที่เรียบง่าย แต่มีประสิทธิภาพน้อยกว่า (เปรียบเทียบสามสตริงแยกกัน) ในเวลาสิบนาที แต่การตระหนักว่ามันเทียบเท่ากับ aaaa [bcd] การค้นหาที่ดีสามารถทำได้โดยค้นหาสี่ตัวแรก 'a' จากนั้นทดสอบอักขระตัวที่ 5 กับ [b, c, d] กระบวนการปรับให้เหมาะสมเป็นหนึ่งในคอมไพเลอร์ที่บ้านของฉันทำงานเมื่อหลายปีก่อนดังนั้นฉันคิดว่ามันยังอยู่ในเอ็นจิ้นนิพจน์ทั่วไปที่ทันสมัยที่สุด

ในทางตรงกันข้ามเครื่องจักรของรัฐมีข้อได้เปรียบบางอย่างเมื่อพวกเขายอมรับสตริงเนื่องจากใช้พื้นที่มากกว่าเมื่อเทียบกับ "การใช้งานเล็กน้อย" พิจารณาโปรแกรมที่จะยกเลิกคำสั่ง escape บนสตริง SQL นั่นคือ: 1) เริ่มต้นและสิ้นสุดด้วยเครื่องหมายคำพูดเดี่ยว 2) เครื่องหมายอัญประกาศเดี่ยวจะถูกหลีกเลี่ยงโดยการเสนอราคาสองครั้งติดต่อกัน ดังนั้น: อินพุต ['a' ''] ควรให้ผลลัพธ์ [a '] ด้วยเครื่องสถานะเครื่องหมายอัญประกาศเดี่ยวติดต่อกันได้รับการจัดการโดยสองสถานะ ทั้งสองสถานะนี้มีจุดประสงค์ในการจดจำประวัติอินพุตเช่นว่าอักขระอินพุตแต่ละตัวจะถูกประมวลผลเพียงครั้งเดียวเท่านั้นดังแสดงในรูปต่อไปนี้:

...
S1->'->S2
S1->*->S1, output *, * can be any other character 
S2->'->S1, output '
S2->*->END, end the current string

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

(แม้แต่ในกรณีเล็ก ๆ น้อย ๆ เช่นการค้นหาสตริงสมาร์ทเอ็นจิ้นสามารถจดจำเส้นทางเดียวในแผนที่สถานะและลดส่วนนั้นลงเป็นการเปรียบเทียบสตริงอย่างง่ายและหลีกเลี่ยงการจัดการสถานะ)

เอ็นจินเฉพาะจากเฟรมเวิร์ก / ไลบรารีอาจช้าเนื่องจากเอ็นจินทำสิ่งอื่น ๆ ที่โปรแกรมเมอร์ไม่ต้องการ ตัวอย่าง: คลาส Regex ใน. NET สร้างกลุ่มวัตถุรวมถึงการจับคู่กลุ่มและการจับภาพ


2
ฉันไม่สามารถพูดได้ดีกว่านี้ สิ่งเดียวที่ฉันจะเพิ่ม: นิพจน์ทั่วไปสามารถชดเชยสำหรับโปรแกรมเมอร์ที่ขี้เกียจ ในตัวอย่างที่คุณกล่าวถึงกับaaaab|aaaac|aaaad aaaa[bcd]มันมีค่าชัดเจนที่ระบุว่าทั้งสองมีความเท่าเทียมกันทางคณิตศาสตร์และผลิต DFA เดียวกันจึงให้โปรแกรมเมอร์อิสระมากขึ้นที่จะเป็นตัวแทนของการแสดงออกปกติในทางที่ทำให้รู้สึก (ไม่ใช่ว่านี่เป็นเรื่องธรรมดา ..
riwalk

ขอบคุณจริง ๆ แล้วมันเป็นเหตุผลที่ต้องขอบคุณคลาสออโตมาตะที่ฉันรับ
lazeR

นี่เป็นตัวอย่างของปัญหาเล็กน้อยที่ regex overkill หรือไม่: stackoverflow.com/questions/18955099/…
Menelaos Bakopoulos

17

นิพจน์ทั่วไปนั้นดูเร็วเพราะคุณมีคอมพิวเตอร์ที่เร็ว

ย้อนกลับไปในปี 1980 เมื่อ 1 MIPS เป็นคอมพิวเตอร์ที่รวดเร็วการแสดงออกปกติเป็นเรื่องที่ค่อนข้างกังวลความกังวลและการวิจัยเพราะมันช้าและน่าเกลียดและคำนวณอย่างเข้มข้น การพัฒนาและช่วยเหลืออัลกอริทึมที่ชาญฉลาด - แต่สำหรับจุดประสงค์ในทางปฏิบัติทุกวันนี้คุณกำลังเห็นความมหัศจรรย์ของเครื่องจักรความเร็วสูง


2
หากคุณกำลังมองหาคำเดียวทั้งสองวิธีจะเหมือนกัน (หรือ regexp ช้ากว่าเล็กน้อย) แต่เมื่อกำหนดนิพจน์ที่ซับซ้อน (และข้อความที่มีขนาดใหญ่พอสมควร) นิพจน์ทั่วไปอาจจะเร็วกว่าการค้นหาแบบง่าย (สมมติว่าคุณเขียนการค้นหาแบบง่าย ๆ เพียงอย่างเดียว (คุณสามารถเขียนการค้นหาที่ซับซ้อนที่รวดเร็ว) ตอนนี้สภาพอากาศเป็นสิ่งสำคัญคำถามทั่วไปเกินไปและคุณจะต้องดูเป็นกรณี ๆ ไป
Martin York

3
-1 ทฤษฎีของการแสดงออกปกติวันที่กลับไปยุค 50 และเป็นเครื่องมือในการสร้างคำศัพท์วิเคราะห์ (และโดยการขยายคอมไพเลอร์) พวกเขาสร้างเครื่องจักรของรัฐที่มีประสิทธิภาพมากซึ่งสามารถพิสูจน์สถานะที่น้อยที่สุดเท่าที่จะทำได้ เครื่องสถานะที่เกิดขึ้นสามารถจับคู่รูปแบบที่ซับซ้อนได้เร็วกว่าสิ่งใด ๆ ที่คุณเขียนด้วยมือ พวกเขาดูเร็วเพราะรวดเร็ว
riwalk

อาจพลาดจุดของฉันไปสักนิด พวกเขาอาจจะ "เร็ว" แต่นั่นก็เป็นญาติทั้งหมด - ยังมีงานอีกมากมายให้ทำ บางคำตอบอื่น ๆ ที่นี่ทนอ่านเช่นกัน
quick_now

คำตอบนี้เกี่ยวข้องกับคำถามหรือไม่ และวิธี upvotes 13?
Sadanand

7

ทำไมคุณคิดว่าพวกเขาเร็วกว่าการค้นหาเอกสาร

มีเทคนิคบางอย่างที่คุณสามารถทำได้เช่น หากคุณกำลังค้นหาคำ 10 ตัวอักษรที่ขึ้นต้นด้วย A และลงท้ายด้วย B ดังนั้นหากคุณพบ A และตำแหน่ง 9 ตัวอักษรต่อไปไม่ใช่ B คุณสามารถข้ามบางส่วนได้ เห็นอัลกอริธึม Knuth – Morris – Pratt


5

อะไรทำให้การแสดงออกปกติรวดเร็ว?

ที่จริงแล้วพวกเขาไม่ได้ ไม่มาก เป็นเพียงการที่พวกเขาไม่ช้าพอที่พวกเราส่วนใหญ่จะสังเกตเห็น ย้อนกลับไปใน 'วันอันเก่าแก่มันเป็นสิ่งที่เห็นได้ชัดเจนมากขึ้น

พวกเขายังไม่ได้เป็นเครื่องมือที่เหมาะสมสำหรับทุกงาน - ค้อน


+1 ขอบคุณสำหรับการเตือนฉันของการทำงานโดยเฉพาะอย่างยิ่งของศิลปะ ...
Yannis

5

RegEx นั้นเร็วกว่าโค้ดที่คุณอาจเขียนเพราะห้องสมุดส่วนใหญ่เป็นผลมาจากนักพัฒนาจำนวนมากที่ใช้เวลาหลายปีในการปรับแต่งเพื่อให้ได้ประสิทธิภาพที่ดีที่สุดเท่าที่จะเป็นไปได้ มันยากสำหรับบุคคลเดียวที่จะทำซ้ำในรหัสการค้นหาของพวกเขาเอง


4
s / สารภาพ / บีบ /?
PéterTörök

4

หลักฐานพื้นฐานของคุณผิด

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

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

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

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

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


1

เป็นไปได้ว่าในภาษาระดับสูงบางภาษา (อาจเป็นจาวาสคริปต์) การใช้ไลบรารี regex ที่ใช้งานในภาษาระดับต่ำ (อาจเป็น C) จะเร็วกว่าการเขียนตัววิเคราะห์คำในภาษาระดับสูง

น่าเชื่อถือ - ฉันไม่รู้ว่านี่เป็นจริงหรือไม่


ทำได้ดีนี่! นั่นคือสิ่งที่ฉันได้พิจารณาด้วย แต่ด้วยตัวประมวลผลของวันนี้เร็วกว่ารุ่นก่อนฉันสามารถพูดได้อย่างปลอดภัยถ้าคุณเขียนรหัสได้อย่างมีประสิทธิภาพคุณจะไม่ค่อยสามารถบอกความแตกต่างได้ จริง ๆ แล้วฉันไม่ใช่คนที่โง่เง่ามากไปกว่าการตั้งสมมติฐานทั่วไปทั้งหมดเร็วขึ้น! ;-)
user3833732
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.