PHP Regular Expressions Regular Expression
PHP Regular Expressions Regular Expression หรือเรียกสั้นๆ regex เป็นเครื่องมือที่มีประโยชน์มากในการค้นหาตัวอักษร คำ หรือ ข้อความรูปแบบต่างๆ ที่เราต้องการจากข้อความอื่นๆ เมื่อค้นหาได้แล้วเราก็อาจจะแทนที่ด้วยข้อความอื่นๆ ได้
การใช้ regex ไม่ได้มีเฉพาะใน PHP นะครับ อย่างใน text editor เช่น vi emacs หรือ ใน Perl VBscript และ shell program อย่างเช่น awk และ sed ก็มีเหมือนกัน แม้กระทั่งใน MySQL ก็มีเช่นกันครับ
Metacharacters
ถ้าคุณต้องการจะใช้ regex ละก็คงหนีไม่พ้นที่จะต้องทำความรู้จักกับ metacharacters ครับ เพราะนอกจากเราจะใช้ตัวอักษรและตัวเลขต่างๆ ในการสร้างรูปแบบ (pattern) ของตัวอักษรที่เราต้องการจะค้นหาแล้ว เราสามารถใช้ metacharacters มาช่วยสร้างรูปแบบอื่นๆ ที่มีความซับซ้อนมากขึ้นได้
เมื่อลองแบ่งประเภทของ Metacharacters อาจแบ่งได้ดังนี้
1. Metacharacters ที่เกี่ยวกับตำแหน่ง (Positioning)
^ | ใช้แทนรูปแบบที่ขึ้นต้นด้วยคำที่กำหนดในตำแหน่งเริ่มต้นของข้อความ เช่น "^the" จะตรงกับข้อความใดๆ ที่ขึ้นต้นด้วย the |
$ | ใช้แทนรูปแบบที่ลงท้ายด้วยคำที่กำหนด เช่น "on the table$" จะตรงกับข้อความใดๆ ที่ลงท้ายด้วย on the table |
. | ใช้แทนตัวอักษรใดๆ 1 ตัวอักษร ยกเว้น newline (n) เช่น "com." จะ ตรงกับ com1 และ coms แต่จะไม่ตรงกับ telecom (เพราะไม่มีตัวอักษรใดต่อท้าย) |
2. Metacharacters ที่เกี่ยวกับจำนวนครั้งที่ปรากฏของตัวอักษร
? | แทนตัวอักษรว่าสามารถจะไม่ปรากฏหรือปรากฏ 1 ครั้ง เช่น ab? จะตรงกับ "a" หรือ "ab" (ตัว b จะไม่ปรากฏ หรือปรากฏ 1 ครั้ง) |
* | แทนตัวอักษรว่าสามารถจะไม่ปรากฏหรือปรากฏได้หลายครั้ง เช่น ab* จะตรงกับ "a", "ab", "abb", "abbb", "abbbb" และ "abbbb..." |
+ | แทนตัวอักษรว่าสามารถจะต้องปรากฏ 1 ครั้ง หรือปรากฏได้หลายครั้ง เช่น ab+ จะตรงกับ "ab", "abb", "abbb", "abbbb" และ "abbbb..." |
{n} | เมื่อ n แทนจำนวนตัวเลข ความหมายก็คือ จะต้องปรากฏ n ครั้ง เช่น ab{4} จะตรงกับ "abbbb" เท่านั้น(b จะต้องปรากฏ 4 ครั้ง) |
{n,} | เมื่อ n แทนจำนวนตัวเลข ความหมายก็คือ จะต้องปรากฏอย่างน้อย n ครั้ง เช่น ab{2, } จะตรงกับ "abb", "abbb", "abbbb" และ "abbbb..." |
{n,m} | เมื่อ n และ m แทนจำนวนตัวเลข ความหมายคือ จะต้องปรากฏอย่างน้อย n ครั้งแต่ไม่เกิน m ครั้ง เช่น ab{2,5} จะตรงกับ "abb", "abbbb" และ "abbbbb" เท่านั้น |
3. Metacharacters ที่กำหนดกลุ่มและช่วงของตัวอักษร
[ ] | แทนตัวอักษรหนึ่งตัว ซึ่งจะปรากฏเป็นตัวอักษรตัวใดตัวหนึ่งใน [ ] เช่น [xy] จะตรงกับ "x", "y", "5x", "abcdx" ถ้าไม่ปรากฏ x หรือ y อยู่เลยก็จะถือว่าไม่ตรง เช่น "qwert" |
- | ใช้ร่วมกับ [ ] แทนช่วงของตัวอักษรหรือตัวเลข เช่น [a-e] จะตรงกับ "1234a", "hello" แต่จะไม่ตรงกับ "HELLO" |
4. Metacharacters อื่นๆ
( ) | ใช้สำหรับจัดกลุ่มตัวอักษรเข้าด้วยกัน หรือกำหนดกลุ่มของรูปแบบย่อย เช่น a(bc)? จะตรงกับ a หรือ abc (ab จะไม่ปรากฏ หรือปรากฏ 1 ครั้ง) |
ใช้เป็น escape character และความหมายอื่นๆ เช่น ถ้าต้องการหา "*" ในข้อความจะต้องใช้ "*" การใช้ baclslash ในอีกความหมายหนึ่งก็คือ ใช้แทน non-printing character เช่น a แทน alarm, BEL character (hex 07), n แทน newline (hex 0A) r แทน carriage return (hex 0D) และ t แทน tab (hex 09) เป็นต้น | |
| | ใช้เป็นทางเลือกว่าจะเลือกค่าที่อยู่ทางซ้ายหรือขวาของ | เช่น "gr(a|e)y" จะตรงกับคำว่า "gray" หรือ "grey" |
5. Metacharacters พิเศษที่แทนกลุ่มของตัวอักษรต่างๆ ซึ่งจะต้องใช้ใน bracket [ ] เสมอ
[:alpha:] | จะตรงกับข้อความที่มีตัวอักษรใดๆ ตั้งแต่ a ถึง z หรือ A ถึง Z หรือเขียนได้เป็น [0-9a-zA-Z] ตรงกับ "ABC", "abc", "aBc" แต่จะไม่ตรงกับ "123" |
[:alnum:] | จะตรงกับข้อความที่มีตัวอักษรและตัวเลข (alphanumeric character) หรือเขียนได้เป็น [0-9a-zA-Z] ซึ่งเท่ากับ [[:alnum:]] เช่น "ab12", "12d" แต่จะไม่ตรงกับ "&*" และ ":;" เป็นต้น |
[:digit:] | จะตรงกับข้อความที่มีตัวเลขอย่างน้อยหนึ่งตัว เช่น "1", "1a2b3c" แต่จะไม่ตรงกับ "abc" เป็นต้น |
[:lower:] | จะตรงกับข้อความที่มีตัวอักษรตัวเล็กอย่างน้อยหนึ่งตัว (lowercase characters) เช่น "xyzabc" แต่จะไม่ตรงกับ "ABC", "B123" และ "123" เป็นต้น |
[:upper:] | จะตรงกับข้อความที่มีตัวอักษรตัวใหญ่อย่างน้อยหนึ่งตัว (lowercase characters) เช่น "XZabc", "A23" แต่จะไม่ตรงกับ "abc", "a123" และ "123" เป็นต้น |
[:space:] | จะตรงกับข้อความที่มี space อย่างน้อย 1 ตัว เช่น " ", "a bc", "12 3" แต่จะไม่ตรงกับ "ab", "abZX" และ "456" เป็นต้น |
[:print:] | จะตรงกับข้อความที่มีตัวอักษรใดๆ ที่สามารถแสดงออกมาได้ (printable character) เช่น "abcX", "124" และ " " แต่จะไม่ตรงกับ "n" (newline) |
[:graph:] | จะตรงกับข้อความที่มี graphical character ยกเว้น space (" ") เช่น "abc", "ab&" และ "1aA" แต่จะไม่ตรงกับ " " |
[:xdigit:] | จะตรงกับข้อความที่มีเลขฐานสิบหก ได้แก่ a ถึง f , 0 ถึง 9 และ A ถึง F เช่น "1B", "0A" แต่จะไม่ตรงกับ "XZ" เป็นต้น |
[:punct:] | จะตรงกับข้อความที่มี punctuation อย่างน้อยหนึ่งตัว เช่น "a;", "a23b?" แต่จะไม่ตรงกับ "abc", "123" และ "AB3" เป็นต้น |
ลองมาดูตัวอย่างที่ซับซ้อนขึ้นมาหน่อยนะครับ
"id.[0-9]" จะตรงกับข้อความในรูปแบบ id ตามด้วยตัวอักษรใดๆหนึ่งตัวและตัวเลขอีกหนึ่งตัว
เช่น "ida1" "idx2" "idc5abc" "id3456" และ แต่จะไม่ตรงกับ "id5x" เพราะ x ไม่ใช่ตัวเลขระหว่าง 1 ถึง 9
"^id.[0-9]$" จะตรงกับข้อความในรูปแบบ id ตามด้วยตัวอักษรใดๆหนึ่งตัวและตัวเลขอีกหนึ่งตัว
เช่น "ida1" "idx2" แต่จะไม่ตรงกับ "idc5abc" "id3456" "dfidf6sdf" "id5x"
"^.{5}$" จะตรงกับข้อความที่มีตัวอักษรหรือตัวเลข 5 ตัวติดกันเท่านั้น
เช่น "abcde" "12345" "a1b2c" แต่จะไม่ตรงกับ "abcdef" "ab1" "123a5bc" เป็นต้น
"a(bc)*" จะตรงกับข้อความที่มีตัวอักษร a อย่างเดียว หรือตามด้วย bc อย่างน้อย 1 ครั้ง
เช่น "a" "abc" "abcbc" "abcbcbc" แต่จะไม่ตรงกับ "abcb" เป็นต้น
"a(bc){2,4}" จะตรงกับข้อความที่มีตัวอักษร "abcbc" "abcbcbc" และ "abcbcbcbc" เท่านั้น และจะไม่ตรงกับ "abcbcbcbcbc"
"a(bc)?" จะตรงกับข้อความ "a" และ "abc" เท่านั้น
"[a-z]" จะตรงกับข้อความที่มีตัวอักษรตัวเล็กตั้งแต่ a ถึง z ในข้อความ
เช่น "x" "a456xcdf" "1234u" แต่จะไม่ตรงกับ "34116" "@#$%" และ "ABC" เป็นต้น
"^[a-zA-Z]" จะตรงกับข้อความที่ขึ้นต้นด้วยตัวอักษรตัวเล็กหรือตัวใหญ่
เช่น "a999" "A dog" และ "ABCD" แต่จะไม่ตรงกับ "2 dogs" "23sdfadg" เป็นต้น
จากตัวอย่างข้างบนถ้าเราเปลี่ยนเป็น "[^a-zA-Z]" ความหมายจะตรงกับข้อความอะไรก็ได้ที่มีตัวอักษรที่ไม่ใช่ตัวอักษรตัวเล็ก หรือตัวใหญ่ปนอยู่ด้วย เช่น "ab%Sd" "abc45" และ "Abc#" แต่ถ้าต้องการให้ตรงกับตัวอักษรตัวแรกของข้อความจะต้องไม่เป็นตัวอักษรตัว เล็กหรือใหญ่ จะต้องใช้รูปแบบเป็น "^[^a-zA-Z]" ซึ่งจะตรงกับ "12AB" และ "#ABc" แต่จะไม่ตรงกับ "ab%Sd" "abc45" และ "Abc#" ส่วน "[^a-zA-Z]$" ก็จะหมายถึงข้อความอะไรก็ได้ที่ไม่ลงท้ายด้วยตัวอักษรตัวเล็กหรือตัวใหญ่ เช่น "AbcD2" และ "abcd%" เป็นต้น
"[0-9]%" จะตรงกับข้อความที่มีตัวเลขแล้วตามด้วย %
เช่น "90%" "90%df" "a4%" "ad7%" แต่จะไม่ตรงกับ "xx%" เป็นต้น
"[0-9][0-9]%" จะตรงกับข้อความที่มีตัวเลข 2 ตัวแล้วตามด้วย %
เช่น "90%" "90%z" "is 90%" แต่จะไม่ตรงกับ "xx%" "ad7%" เป็นต้น
"[0-9][0-9]%$" จะตรงกับข้อความที่มีตัวเลข 2 ตัวแล้วตามด้วย % เท่านั้น ซึ่งจะต้องไม่มีอะไรต่อท้ายเครื่องหมาย %
เช่น "90%" "is 90%" แต่จะไม่ตรงกับ "90%z" "xx%" "ad7%" เป็นต้น
สำหรับ brackets [ ] นั้นจะมีข้อควรระวังเมื่อเรานำ metacharacters เช่น ^ . [ ] $ * + ? { } เข้าไปไว้ใน brackets [ ] แล้วมันจะกลายเป็นตัวอักษรธรรมดาๆ ตัวหนึ่ง โดยความหมายของ metacharacters จะหายไป
ตัวอย่างเช่น "[*][0-9]" จะตรงกับข้อความที่มีตัว * แล้วตามด้วยตัวเลข เช่น "d9x*8x"
จากตัวอย่างที่แล้ว ถ้าเรานำเครื่องหมาย brackets [ ] ที่ครอบ * อยู่ออก ก็จะกลายเป็น "*[0-9]" ซึ่งเมื่อไม่มีเครื่องหมาย brackets อยู่แล้ว จะทำให้ * กลับไปเป็น metacharacters เช่นเดิม และเมื่อทดลองคำสั่งนี้ เราก็จะได้ error ออกมาเป็น Warning: REG_BADRPT...
เพื่อแก้ปัญหานี้เราสามารถนำ escape character ( ) มาช่วย โดยการใส่ เข้าไปข้างหน้า * ก็จะได้เป็น "*[0-9]" ซึ่งก็จะมีความหมายเท่ากับ "[*][0-9]" นั่นเองครับ
สำหรับ Metacharacters พิเศษที่แทนกลุ่มของตัวอักษรต่างๆ นั้นเราสามารถนำมาใช้กำหนดรูปแบบที่เราต้องการได้ เช่น ^[[:alpha:]] จะมีความหมายเท่ากับ ^[a-zA-Z] ในตัวอย่างที่ผ่านมา หรือเราสามารถเขียนในรูปแบบอื่นๆ ได้ เช่น ถ้าต้องการหาข้อความที่ประกอบด้วยตัวเลข 0 ถึง 9 หรือตัวอักษร a ถึง e ก็สามารถเขียนได้เป็น [[:digit:]a-e] ซึ่งจะตรงกับข้อความ เช่น "1" "15" "a" "b0abczvh" แต่จะไม่ตรงกับ "g" และ "hjvz" เป็นต้น
นอกจากนี้มีข้อที่ควรสังเกตอีกประการหนึ่งก็คือ เราสามารถนำเอา regex 2 อันมารวมกันได้ ซึ่งรูปแบบของการเปรียบเทียบก็จะตรงกับรูปแบบของการรวมกันนั้นๆ เช่น "[a-z][0-9]$" ก็จะตรงกับข้อความที่มีตัวอักษร 2 ตัวท้ายเป็นตัวอักษรตัวเล็กตามด้วยตัวเลข เช่น "ASDFz5" และ "1235d0" และก็จะไม่ตรงกับ "ABCD4" เป็นต้น
ตัวอย่างการนำเอา regex หลายๆ ตัวมารวมกัน เช่น "[0-9]{2}-[0-9]{2}-[0-9]{4}" ซึ่งก็จะเป็นรูปแบบ xx-xx-xxxx โดยที่ x แต่ละตัวแทนตัวเลข เช่น 08-04-2002 เป็นต้น ซึ่งถ้าไม่ได้จัดเรียงตัวเลขรูปแบบนี้ก็จะไม่ตรงกับรูปแบบของ regex ที่กำหนด
ขึ้นไปด้านบน