Regular Expression
สมัยที่ผมเริ่มทำงานเป็นโปรแกรมเมอร์ใหม่ ๆ มีครั้งหนึ่งที่ผมต้องแก้ปัญหาโดยการจับ 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