Python re.fullmatch: ตรวจทั้งสตริง ไม่ให้ส่วนเกินหลุดผ่าน
ถ้าใช้ re.search ตรวจรหัสคูปอง แพทเทิร์นอาจไปตรงกลางสตริงแล้วปล่อยให้ขยะนำหน้า/ตามท้ายผ่านได้ re.fullmatch บังคับให้ทั้งสตริงตรงแพทเทิร์นครับ เหมาะกับค่าที่ต้องเป๊ะทั้งก้อน
WHY: ขอบเขตทั้งค่า ไม่ใช่แค่เจอชิ้นส่วน
เหมือนตรวจบัตรคิวที่ต้องตรงเลขทั้งใบ ไม่ใช่แค่เห็นเลขบางหลักในมุม การ validate ชื่อไฟล์ รหัสเชิญ หรือโทเคนสั้น ๆ ถ้าใช้ search อาจรับ xxxTOKENyyy ทั้งที่ต้องการแค่ TOKEN
import re
import unittest
COUPON = re.compile(r"[A-Z0-9]{4}-[A-Z0-9]{4}")
def valid_coupon(raw: str) -> bool:
return COUPON.fullmatch(raw.strip()) is not None
class FullmatchTests(unittest.TestCase):
def test_accepts_exact(self) -> None:
self.assertTrue(valid_coupon("AB12-CD34"))
def test_rejects_prefix_suffix(self) -> None:
self.assertFalse(valid_coupon("xxAB12-CD34"))
self.assertFalse(valid_coupon("AB12-CD34yy"))
def test_search_would_lie(self) -> None:
self.assertIsNotNone(COUPON.search("xxAB12-CD34yy"))
self.assertFalse(valid_coupon("xxAB12-CD34yy"))
if __name__ == "__main__":
unittest.main()
HOW: fullmatch แทนการหุ้ม ^…$ เอง
fullmatch(pattern, string) เทียบเท่าการค้นทั้งสตริงตั้งแต่ต้นจนจบ โค้ดอ่านง่ายกว่าการเขียน ^ กับ $ เองทุกครั้ง และลดโอกาสลืมจุดยึดปลายด้านใดด้านหนึ่ง
ถ้าต้องการไม่สนตัวพิมพ์ ใช้ re.IGNORECASE ตอน compile แล้วทดสอบทั้งเคสผ่านกับเคสมีช่องว่างเกิน
GOTCHA: strip ก่อนหรือไม่
fullmatch มองช่องว่างเป็นตัวอักษร ถ้าอินพุตจากฟอร์มมีช่องว่างข้าง ๆ ให้ strip() ก่อน หรือใส่ช่องว่างในแพทเทิร์นอย่างจงใจ
Recap
- ใช้
fullmatchเมื่อต้องตรงทั้งค่า - อย่าพึ่ง
searchสำหรับ validation แบบเป๊ะ - ตัดสินใจเรื่อง strip / flags ให้สอดคล้องกับสัญญาอินพุต