มาหัดเขียน Regular Expressions กันดีกว่า

มาหัดเขียน Regular Expressions กันดีกว่า Cover Image

Regular Expressions คิดว่าหลายๆคนคงได้ยินหรือรู้จักมาบ้าง แต่จะมีซักกี่คนที่ได้ใช้มันจริงๆจังๆ รวมถึงตัวผมเองด้วย นานๆจะใช้ที ซึ่งจะใช้งานแต่ละครั้งก็ต้องมานั่งเปิด Cheat Sheet ทุกครั้ง

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

TLDR; RegEx Cheatsheet

สัญลักษณ์ ความหมาย
. ทุกตัวอักษรยกเว้นการขึ้นบรรทัดใหม่
\w ทุกๆ ตัวอักษรและ underscore
\W ที่ไม่ใช่ตัวอักษร
\d ตัวเลขทุกตัว
\D ที่ไม่ใช่ตัวเลข
\s whitespace(tab, space, line break)
\S ที่ไม่ใช่ whitespace
[abc] a, b หรือ c อย่างใดอย่างหนึ่ง
[^abc] อะไรก็ได้ที่ไม่ใช่ a,b หรือ c
[a-f] อะไรก็ได้ระหว่าง a ถึง f
^ เริ่มต้น line
$ สิ้นสุด line
\A เริ่มต้นคำ
\z สิ้นสุดคำ
(…) capture group
\1 reference group #1
(a b)
a* ไม่มี a หรือมีก็ได้
a+ a อย่างน้อย 1 ตัว
a? ไม่มี a หรือมี a ได้แค่ 1ตัว
a{5} มี a 5 ตัว
a{2,5} มี a ได้ 2 ถึง 5 ตัว

1. Introduction to Regular Expressions

Regular Expressions คืออะไร ?

Regular Expressions คือ รูปแบบหรือกลุ่มคำ (pattern) ที่เรากำหนดขึ้นเพื่อเอาไว้ค้นหาข้อความหรือตัวอักษรต่างๆ เพื่อเช็คว่าตรงตามเงื่อนไข (pattern) ที่เรากำหนดไว้หรือไม่ Regular Expressions มีอยู่ในแทบทุกภาษา Programming แต่อาจจะแตกต่างกันนิดๆหน่อยๆเท่านั้น

ต้องบอกว่าทุกๆคนเคยใช้ Regular Expressions มาแล้วกันทั้งนั้นเพียงแต่อาจจะไม่ได้อยู่ในรูปของ Programming นั่นเอง ลองนึกถึงโปรแกรมอะไรก็ได้ แล้วเราพยายามค้นหา (Ctrl + F) หรือ Find and Replace นั้นแหละครับเค้าใช้หลักการของ Regular Expressions (ต่อไปจะเรียกสั้นๆว่า regex)

ตัวอย่างการนำ Regular Expressions ไปใช้

  • Validations ฟอร์มต่างๆ เช่น การเช็คว่า ช่องนี้เป็นช่อง email, หมายเลขโทรศัพท์, password หรือโดเมนเนม เป็นต้น
  • ค้นหาคำ ในหน้านั้นๆ หรือ Find & Replace ค้นหาและทำการเปลี่ยนแปลงค่า
  • ป้องกันไม่ให้ผู้ใช้ป้อนคำต้องห้ามต่างๆ เช่น คัดกรอกคำหยาบ
  • การเปลี่ยนชื่อไฟล์ ทีละหลายๆไฟล์พร้อมกัน
  • ตรวจสอบรูปแบบ รหัสนักศึกษา รหัสบัตรประชาชน รหัสบัตรเครดิต เป็นต้น

และรายชื่อด้านล่างนี้ก็เป็นแหล่งอ้างอิงที่ผมใช้ศึกษาทั้งหมด (ขอเขียนเอาไว้ก่อนเลย เผื่อบางคนไม่อยากอ่านบล็อคผม ก็ไปตามอ่านลิงค์ด้านล่าง น่าจะละเอียดกว่า)

2 : Tools & Editors

ในการใช้งาน Regular Expressions สามารถใช้ได้แทบทุกภาษารวมถึงเกือบทุก Editor หรือ IDEs น่าจะมีมาให้หมด ส่วนวิธีการการใช้งาน ก็อาจจะแตกต่างกันเล็กน้อย แต่ concept ยังคงเหมือนกัน ตัวอย่าง Tool Online รวมถึง Editors ต่างๆ คร่าวๆ เช่น

ส่วน Text Editors หรือ IDEs ต่างๆ เช่น Sublime Text 2/3, Brackets หรือ Atom ล้วนรองรับการค้นหาแบบ Regular Expression แทบทั้งนั้น ลองกด ค้นหา (Find) (Ctrl + F5) จะสังเกตเห็นว่ามีการค้นหาแบบ Regular Expression (.*)

IDEs Support RegEx

3 : Basics

พื้นฐานแรกสุดเลยคือเรื่องของ Character classes คือเราสามารถค้นหาคำนั้นๆใน regex ได้เลย เช่น

สมมติเรามีตัวอย่างข้อมูลดังนี้

John
Johny
Joey
Jane
Jack
Jim
James

หากเราต้องการหาชื่อที่มีคำว่า “John” ก็สามารถใช้ regex ได้แบบนี้เลย

John

จะขึ้นผลลัพธ์มาว่า 2 matches นั้นก็คือ เจอทั้ง John และ Johnny

Basic Search

  • . (dot) : เอาไว้ค้นหาตัวอักษรอะไรก็ได้ เช่น regex T.m จะ match Tim, Tom, Tam
  • ^ : สัญลักษณ์เริ่มต้นของ String เช่น ^N... N ขึ้นต้นประโยค จะ match Name แต่ไม่ match FirstName
  • $ : สัญลักษณ์สิ้นสุดของ String เช่น d$ มี d ลงท้ายประโยค จะ match Thailand, Poland, England แต่ละไม่ match Spain

ตัวอย่าง

Regex คำอธิบาย
John ค้นหาแบบคำตรงๆตัวเลย จะ match แค่ John
J... ค้นหาขึ้นตนด้วย J และอีก 3 ตัวเป็นอะไรก็ได้ จะ match กับ John, Joey, Jane, Jack
John|Joey (|) หมายถึงหรือ คือหาคำที่มี John หรือ Joey จะmatch John, Johny, Joey
^J จะมีความหมายคือ เริ่มต้นคำด้วยตัวอักษร J ก็จะ matches ทุกคำ
y$ หมายถึงลงท้ายด้วย ตัวอักษร y ก็จะ match คำว่า Johnny กับ Joey

การค้นหาแบบใช้กลุ่มคำ (character set) ด้วยเครื่องหมาย [] เช่น

[bcd]at

ใน [] จะ match กลุ่มคำของ character เช่นในกลุ่มนี้ มี b,c และ d string ไหนที่ขึ้นต้นด้วย b, c, d จะ match หมด เช่น bat, cat, dat เป็นต้น

เราสามารถใช้เครื่องหมาย - เพื่อกำหนด range ก็ได้ เช่นให้ a ถึง z

[A-Za-z]

เท่ากับว่าหาตัวอักษรภาษาอังกฤษทั้งตัวเล็กและตัวใหญ่ 1 ตัว

หรือ

[0-9]

คือการหาตัวเลข 0 ถึง 9

ตัวอย่างข้างล่างนี้คือสัญลักษณ์ที่ใช้ใน regex

สัญลักษณ์ ชื่อเรียก คำอธิบาย
[abc] character set match character อะไรก็ได้ในกลุ่ม
[^abc] negated set match character อะไรก็ได้ที่ไม่อยู่ในกลุ่มนี้
\w word match ทุกๆ character และ underscore มีค่าเท่ากับ [A-Za-z0-9_]
\W not word match ทุกๆ character ที่ไม่ใช่ word character มีค่าเท่ากับ [^A-Za-z0-9_]
\d digit match ตัวเลข มีค่าเท่ากับ [0-9]
\D not digit match character ที่ไม่ใช่ตัวเลข มีค่าเท่ากับ [^0-9]
\s whitespace match space, tab และ line break)
\S not whitespace match ทุกๆอย่างที่ไม่ใช่ whitespace

4. Special Characters

ใน regex ก็ยังมี special character อื่นๆอีก เช่น การรวมกลุ่มคำ เพื่อเอาไปใช้ reference ในภายหลัง หรือ special character ที่เอาไว้หาตัวอักษรซ้ำๆ เป็นต้น

สัญลักษณ์ ความหมาย
(…) รวมกลุ่มของ pattern เพื่อเอาไว้ใช้ reference ภายหลังได้
\1 reference ถึง group แรก
* หมายถึงศูนย์หรือมากกว่า
+ หมายถึงหนึ่งหรือมากกว่า
? หมายถึงศูนย์หรือหนึ่ง
{1, 3} Quantifier หมายถึง หนึ่งถึงสาม

ตัวอย่างเช่น

  • n+ : คือมี n อย่างน้อยหนึ่งตัว
  • n* : หมายถึง มีหรือไม่มี n ก็ได้
  • n? : หมายถึงไม่มี n เลย หรือมีแค่หนึ่งเท่านั้น
  • n{1,3} : หมายถึงมี n หนึ่งตัวแต่ไม่เกิน 3ตัว

ตัวอย่างการใช้ Group

เช่น เรามีข้อมูลดังนี้

2016-02-11
2016-02-12
2016-03-15
2016-03-30

พอดีว่าต้องการเปลี่ยนแปลง format จาก YYYY-MM-DD เป็น DD/MM/YYYY

เริ่มแรก ก็ต้องใช้ regex ให้ match ทั้งหมด ก็จะได้

\d{4}-\d{2}-\d{2}

ทีนี้ก็ group มันเป็น 3 กลุ่ม

(\d{4})-(\d{2})-(\d{2})

ตอนนี้เราสามารถเข้าถึงค่าแต่ละกรุ๋ปได้แล้วคือ

  • $1 : ได้ค่า 2016
  • $2 : ได้ค่า 02, 03
  • $3 : ได้ค่า 11, 12, 15, 30

ที่นี้ก็มาถึงการ replace ซึ่งถ้าลองเปิด Sublime Text (IDE หรือ Text Editor ตัวอื่นก็ได้ ) แล้วเลือก Find and Replace เราก็สามารถทำแบบนี้ได้เลย

Find and Replace

ข้อมูลใหม่ก็จะกลายเป็นแบบนี้

11/02/2016
12/02/2016
15/03/2016
30/03/2016

หรือถ้าในส่วนของ Programming เช่น JavaScript ก็สามารถ reference group ผ่าน String.replace() ได้เลยเช่นกัน

5. Regular Expressions in JavaScript

มาลองเขียน regex ใน JavaScript กันดูบ้างดีกว่า

flag ต่างๆ ที่สำคัญ เช่น

  • /i : case sensitive เราสามารถกำหนดว่าจะหาข้อมูลแบบ case sensitive หรือไม่
  • /g : global เพื่อให้ match ทั้งหมด ไม่เฉพาะตัวแรกเท่านั้น

การสร้าง regex ใน JavaScript ทำได้ 2 แบบคือ

1. regex literal

สร้างโดยใช้เครื่องหมาย // หรือ //g (global)

let re = /[abc]/;

2. RegExp Object

let re = new RegExp('[abc]');

RegExp.test()

การทดสอบว่า regex ของเรา match กับ string ที่ต้องการหรือไม่ สามารถทำได้ผ่าน regexp.test() ดังเช่น

let re = /[abc]/;

re.test('a') // true

String.match() & String.replace()

การใช้ String.match() เพื่อหา string กับ regex ค่าที่ได้จะส่งกลับมาเป็น array ของข้อมูลที่ match เจอ ตัวอย่าง เช่น

let re = /[abc]/g;

'ant cat dog'.match(re);
// ["a", "c", "a"]

หรือการใช้ String.replace() จากตัวอย่างเรื่อง group ด้านบน


let data = `
2016-02-11
2016-02-12
2016-03-15
2016-03-30
`;
let re = /(\d{4})-(\d{2})-(\d{2})/g

let newData = data.replace(re, '$3/$2/$1')

console.log(newData)

// "11/02/2016
// 12/02/2016
// 15/03/2016
// 30/03/2016"

Done!

Chai Chai Phonbopit : Web Developer @Nimbl3 • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Node.js, JavaScript และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด