Saturday, May 12, 2012

Regular Expression Cheats

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





Regular Expression หรือเรียกย่อๆว่า Regex
หมายถึง รูปแบบของลำดับ หรือกลุ่มของสัญลักษณ์ ที่ใช้แทนลำดับ หรือกลุ่มของอักขระตามที่ต้องการ
regexp ถือเป็น จุดเด่น ของ perl ที่ ภาษาอื่นๆ เอาไปใช้ตาม แต่ปรับเปลี่ยน ให้ดีขึ้น ใช้ง่ายขึ้น ฯลฯ
แล้วก็รูปแบบอาจจะแตกต่างกันนิดๆหน่อยๆ

สัญลักษณ์ของ Regular expression
^
คำ/อักษรที่อยู่หน้าเครื่องหมายนี้ ต้องเป็นคำขึ้นต้นของข้อความที่นำมาตรวจสอบ
เช่น
/^การ/ เป็นการกำหนดว่า คำที่นำมาตรวจสอบต้องขึ้นต้นด้วยคำว่า การ เช่น “การทำดี” “การบ้าน” เป็นต้น คำพวกนี้จะผ่านการทดสอบ

$
คำ/อักษรที่อยู่หน้าเครื่องหมายนี้ ต้องอยู่ตอนท้ายของข้อความที่นำมาตรวจสอบ
เช่น
/มา$/ จะถือว่าคำต่อไปนี้ถูกตามเงื่อนไข “ตามา” “ขอขมา” หรือแม้แต่คำว่า “หมา” แต่คำว่า “ทำดี” จะไม่ผ่าน เพราะไม่ได้ลงท้ายด้วยคำว่า “มา” ตามเงื่อนไขนั่นเอง

+
คำ/อักษรที่อยู่หน้าเครื่องหมายนี้ ต้องมีปรากฏในคำที่นำมาตรวจสอบ อย่างน้อย 1 ตัว
เช่น
/ท+/ จะถือว่าคำต่อไปนี้ผ่านการตรวจสอบ เช่น “ทองจุล” “วันทนา” “ถนนหนทางทุกแห่ง”

?
คำ/อักษรที่อยู่หน้าเครื่องหมายนี้ อาจะมีปรากฏในคำที่นำมาตรวจสอบ หรือไม่ก็ได้ ถ้ามีจะมีกี่ตัวก็ได้
เช่น
/ก?ข+$/ หมายถึง อาจจะมีด้วยตัว ก และอักษรตัวสุดท้ายต้องมีตัว ข อย่างน้อย 1 ตัว (เครื่องหมาย + แสดงว่ามีอย่างน้อย 1 และ เครื่องหมาย $ แสดงว่าเป็นตัวสุดท้าย)

*
ตัวอักษรที่อยู่หน้าเครื่องหมายนี้ จะเป็นตัวอักษรนี้ซ้ำกันกี่ตัวก็ได้ และจะมีหรือไม่มีก็ได้

\s
ช่องว่าง, เว้นวรรค, Space bar หรือ whitespace

.
ใช้แทนตัวอักษรอะไรก็ได้
เช่น
/ก.[0-9]/ หมายถึง ตัว ก ตามด้วยตัวอักษรอะไรก็ได้ และต่อด้วยเลขอารบิค เลข 0-9
/^.{3}$/ หมายถึง ต้องมีตัวอักษรเพียง 3 ตัวเท่านั้น เป็นตัวเลข ตัวอักษร ภาษาไทย ภาษาอังกฤษ ได้ทั้งนั้น

[ ]
ใช้ระบุตำแหน่งในคำว่า ในตำแหน่งนี้จะมีตัวอักษรอะไรได้บ้าง
เช่น
/[นร]/ เป็นการกำหนดว่า คำที่นำมาตรวจสอบ ต้องเป็นตัว น หรือ ตัว ร เท่านั้นจึงจะผ่าน มีความหมายเช่นเดียวกับ “น|ร”
/[ก-ค]/ เป็นการบอกว่า คำที่นำมาจะต้องเป็น ตัว ก ข ค เท่านั้น เช่น ในกรณีเลขประจำตัวที่ขึ้นต้นด้วย ก ข หรือ ค เท่านั้น ถ้าพิมพ์ตัวแรกเป็นตัวอักษรตัวอื่นก็แสดงว่าพิมพ์ผิด เราจะเขียนได้ดังนี้ ^[ก-ค]
/^[a-zA-Z]/ เป็นการบอกว่า คำที่นำมาตรวจสอบต้องขึ้นต้นด้วยตัวอักษร จะเป็นตัวเล็ก คือ a ถึง z หรือ ตัวใหญ่ คือ A ถึง Z ก็ได้
/[0-9๐-๙]%/ เป็นการบอกว่า ให้มีตัวเลข 1 ตัว เลขอะไรก็ได้ เลข 0 ถึง เลข 9 เป็นได้ทั้งเลขไทยและอารบิค ต่อด้วยเครื่องหมาย %
/[ก-๙]/ ตัว ก ถึง ฮ รวมทั้งสระทุกตัว และ ตัวเลขไทย ๐ ถึง ๙
/[0-9๐-๙]/ เลข 0-9 ทั้งเลขไทยและฝรั่ง
/^[0-9๐-๙]+$/ ให้มีเฉพาะตัวเลข 0-9 เลขไทยหรือเลขฝรั่งก็ได้ แต่ห้ามมีตัวอักษรใด ๆ
/^[กข]{3}[-][0-9]$/ ขึ้นต้นด้วยตัว ก หรือ ข จำนวน 3 ตัว ต่อด้วยเครื่องหมาย – และจบด้วยตัวเลขอารบิค เลข 0-9 เช่น “กขก-5” “กกก-3” เป็นต้น สิ่งต่อไปนี้จะไม่ผ่านหรือเป็นเท็จ เช่น “กกกขข” เพราะ ตัวที่ 4 ไม่ใช้เครื่องหมาย – และตัวสุดท้ายไม่ใช่ตัวเลข “ขขข-๘” ตัวเลขสุดท้ายเป็นเลขไทย
ไม่ว่าตัวอักษร หรือสัญลักษณ์ใด ๆ ที่อยู่ภายในเครื่องหมาย [ ] จะกลายเป็นสัญลักษณ์ธรรมดา เช่น + กลายเป็นเครื่องหมายบวก แทนที่จะหมายถึงว่า ต้องมีตัวอักษรอย่างน้อย 1 ตัว

{ }
แสดงจำนวนครั้งที่ซ้ำกัน
เช่น
/กข{2}/ หมายถึงให้มีตัว ข จำนวน 2 ตัว เช่น “กขข”
/กข{2,}/ หมายถึงให้มีตัว ข อย่างน้อย 2 ตัว เช่น “กขขขข”
/กข{3,5}/ หมายถึงให้มีตัว ข จำนวน 3-5 ตัวเท่านั้น คือ “กขขข” “กขขขข” และ “กขขขขข”

( )
ใช้รวมกลุ่มเข้าด้วยกันเป็นส่วนเดียวกัน
เช่น
/ก(ขค)*/ หมายถึง ตัว ก และอาจจะตามด้วยตัว ขค หรือไม่มีตัว ขค ก็ได้ เครื่องหมาย * แสดงว่าจะมีหรือไม่ก็ได้
/ก(ขค){1,5}/ หมายถึง ตัว ก แล้วจะตามด้วย ขค จำนวน 1-5 ชุด เช่น “กขคขคขค” หรือ “กขคขค” ก็ได้

|
เสนอทางเลือกอย่างใดอย่างหนึ่ง
เช่น
/การ|ความ/ เป็นการบอกว่า จะใช้คำว่า การ หรือ ความ ก็ได้
/(ก|ขค)งจ/ เช่น กงจ หรือ ขคงจ ก็ได้

^[1-9][0-9]*$
ขึ้นต้นด้วยเลข 1-9 และอาจจะต่อด้วย เลข 0-9 กี่ตัวก็ได้ ในกรณีนี้ ถ้าเป็นเลข 0 ก็จะไม่ผ่าน จะผ่านตั้งแต่ 1 2 3 4 ไปเรื่อย ๆ

^(0|[1-9][0-9]*)$
อาจจะขึ้นต้นด้วยเลข 0 หรือเลข 1-9 ก็ได้ และอาจจะต่อด้วยเลข 0-9 ในกรณีนี้ เราใช้ตรวจสอบการพิมพ์ที่เป็นตัวเลขตั้งแต่ 0 ขึ้นไป ถ้ามีตัวอักษร ก็จะไม่ผ่านการตรวจสอบ หรือ เป็นเท็จ นั่นเอง

^(0|-?[1-9][0-9]*)$
เหมือน ^(0|[1-9][0-9]*)$ เพียงแต่ ถ้าไม่ขึ้นต้นด้วยเลข 0 สามารถมีเครื่องหมาย ลบ ได้ หรือจะไม่มีเครื่องหมายลบ ก็ได้ เครื่องหมาย ? แสดงว่า จะมีหรือไม่มี ก็ได้

^[0-9]+(\.[0-9]+)?$
ขึ้นต้นด้วย 0-9 อย่างน้อย 1 ตัว และอาจจะมี จุดและต่อด้วยตัวเลข 0-9 อย่างน้อย 1 ตัว อย่างนี้ เป็นการบอกว่าจะทศนิยมหรือไม่มีก็ได้ (สังเกตเครื่องหมาย ? อยู่หลังกลุ่มทั้งหมดซึ่งอยู่ในวงเล็บ เป็นการบอกว่า กลุ่มนี้ คือ (\.[0-9]+) จะมีหรือไม่มีก็ได้) แต่จะมีแค่ จุดเฉย ๆ เช่น 15. อย่างนี้ไม่ได้ ต้องเป็น 15.2 หรือ 15.38 ก็ได้ (เพราะเครื่องหมาย + อยู่หลัง [0-9] แสดงว่า ตำแหน่งนี้ คือต่อจาก จุด ยังไง ๆ ก็ต้องมีตัวเลข 0 ถึง 9 อย่างน้อย 1 ตัว จะเป็น 2 ตัว 5 ตัว 10 ตัว ก็ได้)

^[0-9]+(\.[0-9]{2})?$
เหมือนข้างบน แต่บังคับว่า ถ้ามีทศนิยม ทศนิยมต้องมี 2 ตำแหน่งเท่านั้น เครื่องหมาย {} กำหนดว่าจะต้องมีซ้ำกี่ครั้ง

^[0-9]+(\.[0-9]{1,2})?$
เหมือนข้างบน แต่อนุญาตให้มีทศนิยม 1 หรือ 2 ตำแหน่ง สังเกตการเขียนตัวเลข ในระหว่างเครื่องหมาย { และ }

^[0-9]{1,3}(,[0-9]{3})*(\.[0-9]{1,2})?$
ต้องขึ้นต้นด้วยตัวเลข 0-9 หรือ อาจจะตามด้วยเครื่องหมาย คอมม่า และตัวเลข 0-9 อีก 3 ตัว และอาจจะต่อด้วยทศนิยม 1 หรือ 2 ตำแหน่ง

^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(\.[0-9]{1,2})?$ เหมือนข้างบน แต่กำหนดให้การมีเครื่องหมาย คอมม่า อาจจะมีหรือไม่มีก็ได้ วิธีกำหนดทางเลือกใช้เครื่องหมาย | แทนที่จะใช้ ? การเลือกใช้ต้องอยู่ที่เราจะตัดสินใจว่าจะเลือกใช้อะไรจึงจะเหมาะสม นี่แหละเสน่ห์ของการเขียนโปรแกรม มีวิธีการหลายอย่างที่จะได้มาซึ่งผลลัพธ์อย่างเดียวกัน แต่อย่างไหนจะเหมาะ ต้องเลือกดู เลือกใช้ให้เหมาะสม




อัขระพิเศษที่ใช้ใน regexp
[] range specificication (e.g., [a-z] means a letter in the range a to z)
\w letter or digit; same as [0-9A-Za-z]
\W neither letter or digit
\s space character; same as [ \t\n\r\f]
\S non-space character
\d digit character; same as [0-9]
\D non-digit character
\b backspace (0x08) (only if in a range specification)
\b word boundary (if not in a range specification)
\B non-word boundary
* zero or more repetitions of the preceding
+ one or more repetitions of the preceding
{m,n} at least m and at most n repetitions of the preceding
? at most one repetition of the preceding; same as {0,1}
| either preceding or next expression may match
() grouping




ตัวอย่างการใช้งาน regexp แบบทั่วๆไป
/[abcde]/ # เทียบได้กับ ตัวอักษร a, b, c, d,e

/[0123456789]/ # เทียบได้กับ ตัวเลขใดๆหนึ่งตัว

/[0-9]/ # เทียบได้กับ ตัวเลขใดๆหนึ่งตัว

/[a-zA-Z0-9_]/ # เทียบได้กับ ตัวเลข, ตัวอักษร หรือ ขีดล่าง หนึ่งตัว

/[^0-9]/ # เทียบได้กับอะไรก็ได้หนึ่งตัว ที่ไม่ใช่ตัวเลข

/[^aeiouAEIOU]/ # เทียบได้กับอะไรก็ได้หนึ่งตัว ที่ไม่ใช่สระในภาษาอังกฤษ

/\d/ #มีค่าเท่ากับ /[0-9]/

/\D/ #มีค่าเท่ากับ /[^0-9]/

/\w/ #มีค่าเท่ากับ /[a-zA-Z0-9_]/

/\W/ #มีค่าเท่ากับ /[^a-zA-Z0-9_]/

/\s/ #มีค่าเท่ากับ /[\r\t\n\f]/

/\S/ #มีค่าเท่ากับ /[^\r\t\n\f]/




ตัวอย่างการใช้งาน regexp แบบ Multi-character Patterns หรือ Grouping Patterns
ในข้อข้อนี้เราจะมีสัญญาลักษณ์อยู่ 3 ตัว คือ
* หมายความว่า ศูนย์หรือมากว่า
+ หมายความว่า หนึ่งหรือมากว่า
? หมายความว่า ศูนย์หรือหนึ่ง

เช่น
/x+/ # หมายถึงมี x อย่างน้อยหนึ่งตัว
แล้วถ้าสมมุติว่าเราต้องการบอกว่ามี x ตั้งแต่ 5 ถึง 10 ตัว
เราสามารถเขียนเป็น /x{5,10}/ เราอาจใช้วิธีเขียนแบบนี้แทนการใช้ *, +, ? ได้เป็น {0,}, {1,},{0,1}

และยังมีอีกเครื่องหมายหนึ่งที่ใช้อื่นๆอีก เช่น

/song|blue/ # ใช้เครืองหมาย | หมายถึงเป็น คำว่า song หรือคำว่า blue ก็ได้

/^real/ # ใช้เครืองหมาย ^ หมายถึง string ที่ขึ้นต้นด้วยคำว่า real

/real$/ # ใช้เครืองหมาย $ หมายถึง string ที่ลงท้ายด้วยคำว่า real




ตัวอย่างการใช้งาน regexp แบบ Multi-character Patterns หรือ Grouping Patterns เพิ่มเติม
. ก็คือตัวอะไรก็ได้ ไม่ว่าจะเป็น ช่องว่าง หรือว่า a ก็ ใช้ . แทนได้หมด
.+ คือ ตัวอะไรก็ได้ กี่ตัวก็ได้ แต่ต้องมีอย่างน้อย 1 ตัว (ไม่มีไม่ได้)
? คือ ตัวอะไรก็ได้ 1 ตัว ซึ่งจะมีหรือไม่มีก็ได้

.a คือ ตัวอะไรก็ได้รวมถึงเครื่องหมายเว้นวรรคต่างๆ 1 ตัว แต่ต้องตามด้วย a เช่น aa ba ca 5a 9a pa หรือแม้กระทั่ง เว้นวรรคa
a.a คือ ตัว a แล้วตามด้วยตัวอะไรก็ได้ แล้วตามด้วย a เช่น a0a aaa asa รวมถึง aเว้นวรรคa แต่ว่า aa เฉยๆ ไม่ได้ (ต้องมี 3 ตำแหน่งเท่านั้น)

.? คือ ตัวอะไรก็ได้รวมถึงเครื่องหมายเว้นวรรคต่างๆ 1 ตัว แต่จะมีหรือไม่มีก็ได้
a.? คือ ตัว a แล้วตามด้วยตัวอะไรก็ได้ จะมีหรือไม่มีก็ได้ เช่น aเฉยๆ aเว้นวรรค aa as a1 ae แต่ sa ไม่ใช่ (ต้องขึ้นด้วย a เท่านั้น)
a.?a คือ ตัว a แล้วตามด้วยตัวอะไรก็ได้ จะมีหรือไม่ก็ได้ แต่ต้องตามด้วย a เช่น asa aaa a0a aoa aเว้นวคครa หรือ aa

.+ คือ ตัวอะไรก็ได้รวมถึงเครื่องหมายเว้นวรรคต่างๆ กี่ตัวก็ได้
a+ คือ ตัว a กี่ตัวก็ได้ เช่น aa aaaaaa aaaaaaaaa รวมถึง a เฉยๆ แต่ aaaaaaaaaas ไม่ใช่ (ต้องมีแค่ a เท่านั้น)
a.+ คือ a แล้วตามด้วยตัวอะไรก็ได้ กี่ตัวก็ได้ เช่น a0000000000 askjkljhi906klsd a9 a8a a666 aเว้นวรรค0259skfk
a.+a คือ a แล้วตามด้วยตัวอะไรก็ได้ กี่ตัวก็ได้ แต่ต้องตามหลังด้วย a เช่น aaa asa aเว้นวรรคa assssssssa a23s554a aเว้นวรรคเว้นวรรคเว้นวรรคa แต่ aa ไม่ใช่ เพราะ ต้อง 3 ตำแหน่งขึ้นไปเท่านั้น

ดังนั้น การเขียน regexp เวลาเจอคำที่พลิกแพลง random มา
เช่น D UaN G E OaN หรือ D U NaGaE OaN
ให้ใส่ไปว่า D.U.N.G.E.O.N ก็จะถึอว่า match ทั้งหมด (เจอหมด)




สรุป
regexp จริงๆ แล้ว ถ้าได้ใช้บ่อยๆ เราก็จะคล่อง
เมื่อคล่อง เราก็จะรู้สึกว่าง่ายเองแหละครับ

[บทความนี้ จริงๆ อยู่ใน opkwin.com ตั้งแต่ราวๆ ปี 2007 มั้ง
พอดีมีคนถามใหม่ ใน facebook page ของ piratepeer.com ก็เลยเอามาสรุป ลงในนี้อีกที]

No comments:

Why You Don't LIKE My FaceBook Fanpage ?
×
blogger