คู่มือการใช้ไพวิกิพีเดีย/นิพจน์ปรกติในไพวิกิพีเดีย

<ns>10</ns>
 <id>1777</id>
 <revision>
 <id>26217</id>
 <parentid>26028</parentid>
 <timestamp>2013-02-07T09:19:04Z</timestamp>
 <contributor>
 <username>Tiemianwusi</username>
 <id>2084</id>
 </contributor>
 <origin>26217</origin>
 <model>wikitext</model>
 <format>text/x-wiki</format>
ในไพวิกิพีเดีย อาจจะมีการใช้นิพจน์ปรกติในสองโอกาส คือในการใช้งานสคริปต์ replace.py หรือไม่ก็ใช้ในการเขียนสคริปต์ เนื่องจากไพวิกิพีเดียเขียนขึ้นด้วยภาษาไพทอน นิพจน์ปรกติของไพวิกิพีเดียจึงอาศัยนิพจน์ปรกติของภาษาไพทอนเป็นฐาน ส่งผลให้วากยสัมพันธ์เหมือนกันทุกประการ
นิพจน์ปรกติของภาษาไพทอนรองรับความสามารถของนิพจน์ปรกติของภาษาเพิร์ล ซึ่งมีความสามารถเพิ่มเข้ามามากมายเทียบกับมาตรฐานนิพจน์ปรกติทั่วไป
เพื่อแยกแยะระหว่างนิพจน์ปรกติทั่วไปกับข้อความ จะขอเขียนนิพจน์ปรกติคร่อมด้วยเครื่องหมาย <code>/.../</code> แทนที่จะคร่อมด้วย "..." ตามปกติ อย่างไรก็ตาม ขอให้เข้าใจว่าในภาษาไพทอนนิพจน์ปรกติคร่อมด้วย "..." เหมือนข้อความทั่วไป
ต่อจากนี้จะแสดงถึงความสามารถหรือวากยสัมพันธ์เฉพาะของนิพจน์ปรกติบนไพวิกิพีเดีย/ภาษาไพทอนพอเป็นสังเขปเท่านั้น โดยจะไม่ลงลึกถึงการใช้งานนิพจน์ปรกติ และอาจมีตัวอย่างประกอบเพื่อให้เข้าใจได้ง่าย
อักขระควบคุม.
อักขระควบคุม (metacharacters) เป็นเครื่องหมายพิเศษที่ใช้ในการควบคุมรูปแบบของข้อความ ได้แก่
ตารางด้านล่างนี้จะอธิบายเฉพาะอักขระที่มีความกำกวมในการใช้อย่างย่อเท่านั้น
การหนีอักขระด้วยเครื่องหมายทับหลัง.
อักขระสัญลักษณ์โดยส่วนใหญ่จะเป็นอักขระควบคุมด้วย จึงไม่สามารถใส่อักขระสัญลักษณ์โดด ๆ เพื่อให้นิพจน์ปรกติจับได้ ทางออกที่จะให้นิพจน์ปรกติจับกับตัวสัญลักษณ์เหล่านั้น คือการหนีอักขระดังกล่าว (escape character) โดยให้ใส่เครื่องหมายทับหลัง (<code>\</code>) เข้าไปก่อนหน้าสัญลักษณ์ต่าง ๆ ลักษณะเดียวกันกับ <code>\n \r \0</code>
เช่นต้องการจะจับกับข้อความ "a+" ในข้อความ "qwea+ewqaaaqwe" หากใช้นิพจน์ปรกติ <code>/a+/</code> จะเป็นการจับกับ "a" และ "aaa" ใน "qwea+ewqaaaqwe" แทน เพราะ <code>+</code> เป็นอักขระควบคุมในการจับซ้ำ แต่ถ้าใช้นิพจน์ปรกติ <code>/a\+/</code> ก็จะจับได้ "a+" ใน "qwea+ewqaaaqwe" ตามที่ต้องการ
เครื่องหมายทับหลัง (<code>\</code>) ควรใส่เข้าไปก่อนหน้าเครื่องหมายทุกอย่างที่จะจับ (ควรใช้กับทุกอักขระที่ไม่ใช่ alphanumeric characters หรือก็คือ อักขระทุกตัวที่ไม่ใช่ตัวอักษร ตัวเลข และเครื่องหมายขีดล่าง ('_')) ถึงแม้ว่าสัญลักษณ์ดังกล่าวจะไม่ใช่อักขระควบคุมก็ตาม เพื่อให้ไม่เกิดความกำกวม อย่างไรก็ตามในทางปฏิบัติ หากการเขียนอักขระนั้นโดด ๆ ไม่ทำให้เกิดความหมายพิเศษ ก็ไม่จำเป็นจะต้องหนีอักขระดังกล่าวเสมอไป เช่น เครื่องหมาย # @ ! < >
ชุดอักขระ.
ชุดอักขระ (character set) คือกลุ่มของอักขระที่นิยามมาให้แล้ว ตารางด้านล่างนี้แสดงชุดอักขระทั้งหมด
นอกจากนี้ ยังมีชุดอักขระซึ่งมีความยาวเป็นศูนย์ กล่าวคือเป็นรูปแบบที่นิพจน์ปรกติต้องพยายามจับเพื่อดำเนินการต่อไป แต่เมื่อจับได้แล้วจะไม่นำอักขระเหล่านี้มาประมวลผล ตารางด้านล่างนี้แสดงชุดอักขระความยาวศูนย์ทั้งหมด
โลภกับไม่โลภ.
การจับข้อความซ้ำโดยเครื่องหมาย <code>*</code> หรือ <code>+</code> จะพยายามจับให้ไกลที่สุดเท่าที่เป็นไปได้ไปก่อน
หากไม่ต้องการให้มีการจับแบบโลภ กล่าวคือพยายามหยุดการจับซ้ำทันที่ถ้าเป็นไปได้ ให้ใส่เครื่องหมาย <code>?</code> เข้าไปด้านหลังเครื่องหมาย <code>*</code> หรือ <code>+</code> เพื่อให้นิพจน์ปรกติพยายามที่จะหยุดการจับซ้ำทันทีที่สามารถจับอักขระถัดไปได้
ตัวอย่างเช่น สำหรับข้อความ "abcdbcdbc" ตัวอย่างการจับซ้ำแบบ"โลภ" คือใช้นิพจน์ปรกติ <code>/b.*d/</code> ซึ่งจะได้ "bcdbcd" จาก "abcdbcdbc"
หากต้องการจะจับให้ได้ "bcd" จาก "abcdbcdbc" แทนที่ "abcdbcdbc" ก็ต้องทำการจับแบบไม่"โลภ" นั่นคือใช้นิพจน์ปรกติ <code>/b.*?d/</code> แทน
โหมด.
โหมด (mode, flag) เป็นลักษณะของการประมวลผลรูปแบบที่แตกต่างกันออกไป มีทั้งหมดดังนี้
ในการใช้งาน replace.py อาจมีบางโหมดที่สามารถกำหนดได้จากพารามิเตอร์ เช่น โหมด dotall และ ignorecase (nocase) และโหมดทั้งหลายสามารถเรียกใช้พร้อมกันได้ด้วย เช่น <code>python replace.py -regex -dotall -nocase "Abc.*" "def" -page:xxx</code> หากหน้า "xxx" มีข้อความ
ก็จะถูกแทนที่เป็น
แต่บางโหมดเช่น multiline ไม่มีพารามิเตอร์ให้ใช้ในการเปิดโหมด ก็อาจใช้ inline flag ในการกำหนด โดยใส่ <code>(?"flag1flag2flag3...flagN")</code> ไว้ด้านหน้าสุดของข้อความ โดยที่ "flag1" "flag2" ... "flagN" เป็นค่า inline flag ที่ปรากฎในตารางด้านบน เช่น หากต้องการกำหนด multiline กับ ignorecase พร้อมกัน ก็อาจใช้ <code>python replace.py -regex "(?mi)^ *Q" "z" -page:xxx</code> หากหน้า "xxx" มีข้อความ
ก็จะถูกแทนที่เป็น
สำหรับ การเขียนโปรแกรมภาษาไพทอน สามารถกำหนดโหมดได้ผ่านพารามิเตอร์เพิ่มเติม หากต้องการระบุหลาย ๆ โหมดพร้อมกัน ให้ใช้ vertical bar (<code>|</code>) คั่น เช่น
สำหรับการแทนที่ข้อความ ก็มีลักษณะแบบเดียวกัน
หรือไม่เช่นนั้นก็อาจใช้ inline flag คล้ายกับที่เคยกล่าวมาแล้วก็ได้
การอ้างย้อนหลัง.
การอ้างย้อนหลัง (backreference) คือความสามารถในการจับข้อความจาก"ข้อความค้นหา" มาใส่อีกครั้งใน"ข้อความค้นหา"ด้วยกันเอง หรือจะจับมาใส่ใน"ข้อความแทนที่"ก็ได้ โดยกำหนดข้อความที่จะจับจาก capturing group (<code>(...)</code>) ใน"ข้อความค้นหา" และใช้รหัสอ้างย้อนหลัง (<code>\1 \2 \3 ...</code>) ในการอ้างย้อนหลัง ซึ่งรหัสอ้างย้อนหลังนี้จะปรากฎใน "ข้อความค้นหา" หรือ "ข้อความแทนที่" ก็ได้
สำหรับข้อความที่ต้องการจะจัดกลุ่ม แต่ไม่ต้องการจับให้มาอ้างในภายหลัง สามารถใช้ non-capturing group (<code>(?:...) </code>) ได้
ตัวอย่างการใช้การอ้างย้อนหลังกับรูปแบบด้วยกันเอง เช่น ต้องการจะจับข้อความที่มีวรรณยุกต์ตัวเดียวกันซ้อน ได้แก่ "่่" "้้" "๊๊" "๋๋" ก็อาจเขียนเป็นนิพจน์ปรกติได้ว่า <code>/([่้๊๋])\1/</code> ซึ่งจะทำให้ในข้อความ "เทวะ, อันข้้านี้ไซร้ มานี่้อย่่างไร บทราบสำนึกสักนิด" มีการจับ "้้" และ "่่" จาก "เทวะ, อันข้้านี้ไซร้ มานี่้อย่่างไร บทราบสำนึกสักนิด" สังเกตว่า "่้" จาก "มานี่้" จะไม่ถูกจับเนื่องจาก "่" กับ "้" เป็นคนละอักขระกัน แต่หากใช้นิพจน์ปรกติ <code>/[่้๊๋]{2}/</code> ก็จะจับกรณีนี้ด้วย
ตัวอย่างการใช้การอ้างย้อนหลังกับข้อความแทนที่ เช่น หากต้องการจะแทนที่ → (ตัวอย่างคือ →) ก็อาจกำหนด"ข้อความค้นหา"เป็น <code>/\{\{เรตติง-(.*?)|(.*?)\}\}/</code> และข้อความแทนที่เป็น <code>""</code>
การยืนยันด้วยอักขระความยาวศูนย์.
การยืนยันด้วยอักขระความยาวศูนย์ (zero-width assertion) หรือที่รู้จักกันในชื่อ lookaround เป็นรูปแบบซึ่งนิพจน์ปรกติจะพยายามจับข้อความนั้น แต่ไม่นับข้อความนั้นเป็นข้อความที่ค้นเจอ ประกอบไปด้วย
ตัวอย่างเช่น สมมุติมีข้อความ
หากต้องการจะจับ หรือ โดยที่ไม่ยุ่งกับข้อความที่อยู่ใน ... อาจมองปัญหาใหม่เป็นการจับ หรือ โดยที่จะต้องไม่มี เป็นข้อความอยู่ด้านหลัง ยกเว้นกรณีที่เจอ ก่อน (หากเจอ ก่อนแสดงว่าจริง ๆ แล้วยังไม่ได้เริ่มแท็ก)
จากปัญหาข้างต้น สามารถเขียนนิพจน์ปรกติออกมาได้ว่า <code></?b>(?!(?:(?!</?nowiki>).)*)</code>