Regular Expression

Chokchai Phatharamalai
odds.team
Published in
2 min readJun 10, 2024
Photo by Jason Leung on Unsplash

สมัยที่ผมเริ่มทำงานเป็นโปรแกรมเมอร์ใหม่ ๆ มีครั้งหนึ่งที่ผมต้องแก้ปัญหาโดยการจับ pattern เพื่อตรวจสอบว่ารหัสหนังสือในห้องสมุดตรงตามรูปแบบที่กำหนดไหม ผมพยายามแก้ปัญหาอยู่นานก็แก้ไม่สำเร็จสักที แล้วก็มีเพื่อนในทีมชื่อรองเข้ามาช่วย แก้แป๊บเดียวเสร็จ โค้ดที่ใช้แก้มีแค่บรรทัดเดียวด้วยซ้ำ ผมประหลาดใจมาก ผมถามน้องรองว่า “สิ่งนี้มันคืออะไร?!” น้องรองตอบกลับมาด้วยน้ำเสียงเรียบเฉยว่า “regular expression”

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

ถ้าเรามีปัญหา 1 ปัญหา แล้วเลือกใช้ regular expression แก้ปัญหา เราจะมีปัญหาเพิ่มเป็น 2 ปัญหา 🤣

ตั้งแต่นั้นเป็นต้นมา regular expression ก็เหมือนยาขมของชีวิตผม เจอเมื่อไหร่ก็ค่อย ๆ หลีกหนีมัน ทุกวันนี้เรียกว่าอ่านมันออก แต่ไม่เคยคิดจะเลือกเขียนเองเลย

แล้ววันหนึ่ง ผมก็เจอบทความที่เขียนเกี่ยวกับการใช้ regular expression ในการเช็คว่าเลขที่ส่งเข้ามาเป็นเลขจำนวนเฉพาะไหม

def is_prime(n)
('🍎' * n) !~ /^🍎?$|^(🍎🍎+?)\1+$/
end

เจอปุ๊บผมก็ไม่พูดพล่ามทำเพลง ผมเอาโค้ดนี้โยนให้ ChatGPT อธิบายให้ฟัง

ได้คำอธิบายมาดังนี้

ประกาศ function

def is_prime(n)

ประกาศ function is_prime ที่รับ parameter ตัวเดียวคือ n

คูณ string

('🍎' * n)

เรากำลังคูณ string 🍎 ด้วย n ในภาษา Ruby เวลาเราเอาตัวเลขคูณกับ string กับตัวเลข จะทำให้ได้ string นั้นซ้ำ n ตัว เช่น ถ้าคูณด้วย 5 ก็จะได้ 🍎🍎🍎🍎🍎

พยายาม match Regular Expression

!~ /^🍎?$|^(🍎🍎+?)\1+$/

โค้ดส่วนนี้ใช้เครื่องหมาย !~ เพื่อเช็คว่า string ที่ส่งเข้ามาต้องไม่ match regular expression นี้นะ

แยกองค์ประกอบ regular expression นี้กัน

^🍎?$ ส่วนนี้พยายาม match 🍎 0 หรือ 1 ผล ซึ่ง 0 กับ 1 ไม่นับเป็นจำนวนเฉพาะ

| คือ เครื่องหมาย หรือ ซึ่งจะ match ฝั่งซ้ายหรือขวาก็ได้

^(🍎🍎+?)\1+$ ส่วนนี้ค่อนข้างซับซ้อน

  • ^ เป็นจุดเริ่มต้นของ string
  • (🍎🍎+?) จับกลุ่มแอ๊ปเปิ้ลตั้งแต่ 2 ผลขึ้นไป
  • \1+ เช็คว่าต้องมีตั้งแต่ 1 กลุ่มขึ้นไป
  • $ เป็นจุดท้ายสุดของ string

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

เรียกว่าเป็นครั้งแรกในชีวิตเลยที่มอง regular expression แล้วอดชมไม่ได้ว่ามัน ‘สวย‘

ที่ผมเอาเรื่องนี้มาแบ่งปันกับทุกคนเพราะ regular expression ก็เหมือนชีวิต เวลาผมโดนขอให้นึกถึงงานที่ประทับใจที่สุดในชีวิต คำตอบที่ปรากฏมักจะไม่ใช่งานที่ทุกอย่างลงตัว ราบรื่น สนุกสนาน แต่มันกลับเป็นช่วงเวลาที่เลวร้าย ขมขื่น ยากเย็นแบบที่ในช่วงเวลาในอดีตนั้น นึกไม่ออกเลยว่าจะผ่านมันไปได้ยังไง แต่พอวันเวลาผ่านไปแล้วผมได้มองย้อนกลับไป มันกลับกลายเป็นความทรงจำที่สวยงามอย่างไม่น่าเชื่อ ทั้ง ๆ ที่ตอนตรากตรำกับมันนั้น ช่างยากเย็นเหลือเกิน

ในอดีตตอนผมพยายามปล้ำกับ regular expression ผมก็ไม่มีวันเชื่อหรอก ว่าวันหนึ่งผมจะเจอ regular expression ที่ทำให้ผมยอมรับจากใจได้ว่ามันสวย

ปิดท้ายด้วย quote จาก Virginia Satir ละกัน

ชิมให้ครบทุกอย่าง และเลือกกลืนเฉพาะของที่ชอบเท่านั้น — Virginia Satir

อ้างอิง

--

--