บทความทั้งหมด

การ Escape สตริง: ทำไมกฎถึงต่างกันใน JS, JSON, shell และ regex

ภาษาไทยเขียนวรรณยุกต์และสระบางตัวเป็นเครื่องหมายที่ลอยอยู่เหนือหรือใต้พยัญชนะ (combining marks) เช่นคำว่า "กี่" ประกอบด้วยพยัญชนะ สระ และวรรณยุกต์ซ้อนกันในตำแหน่งเดียว เมื่อเปิดใช้ตัวเลือก escape อักขระนอก ASCII เป็น \uXXXX แต่ละองค์ประกอบเหล่านี้จะถูกแยก escape เป็นลำดับ \uXXXX ของตัวเอง — ตัวอักษรที่มองเห็นเป็น "หนึ่งตัว" บนหน้าจออาจกลายเป็นหลายลำดับ escape ที่ต้องเรียงต่อกันอย่างถูกต้อง ไม่เช่นนั้นการเรนเดอร์กลับจะผิดตำแหน่งวรรณยุกต์

Escape ในสตริง JavaScript/JSON

ในลิเทอรัลสตริงของ JS และใน JSON อักขระพิเศษจะถูก escape ด้วยแบ็กสแลช: \" สำหรับเครื่องหมายคำพูด, \n สำหรับการขึ้นบรรทัดใหม่, \\ สำหรับแบ็กสแลชเอง นอกจากนี้ JSON ยังกำหนดให้ทุกสตริงต้องใช้เครื่องหมายคำพูดคู่ — ต่างจาก JS ที่อนุญาตให้ใช้เครื่องหมายคำพูดเดี่ยวได้ด้วย

Escape ในคำสั่งเชลล์

ในบรรทัดคำสั่ง อักขระพิเศษได้แก่ ช่องว่าง เครื่องหมายคำพูด เครื่องหมายดอลลาร์ เครื่องหมายดอกจัน และอื่นๆ — อักขระเหล่านี้มีความหมายพิเศษสำหรับเชลล์ ช่องว่างภายในอาร์กิวเมนต์ของคำสั่งต้อง escape หรือครอบทั้งอาร์กิวเมนต์ด้วยเครื่องหมายคำพูด ไม่เช่นนั้นเชลล์จะแยกมันออกเป็นสองอาร์กิวเมนต์

Escape ในนิพจน์ปกติ (regular expression)

ในนิพจน์ปกติ อักขระอย่างจุด ดอกจัน หรือวงเล็บมีความหมายพิเศษ (อักขระใดก็ได้, ตัวระบุจำนวน, กลุ่ม) เพื่อให้จับคู่แบบตัวอักษรจริงแทนที่จะเป็นเมทาแคแรกเตอร์ ต้องใส่แบ็กสแลชไว้ข้างหน้า: \. จับคู่จุดจริงๆ ไม่ใช่ "อักขระใดก็ได้"

ทำไมแต่ละบริบทจึงต้องการ escape ของตัวเอง

ข้อผิดพลาดแบบ "escape ซ้ำสองครั้ง" หรือ "escape ไม่ครบ" เป็นสาเหตุที่พบบ่อยที่สุดอย่างหนึ่งที่ทำให้โค้ดพังเมื่อแทรกข้อความจากผู้ใช้ (เช่น path ไฟล์ที่มีช่องว่าง) ลงในคำสั่งหรือสตริง การ escape ที่ถูกต้องขึ้นอยู่กับว่าข้อความนั้นถูกแทรกเข้าไปที่ใดกันแน่ ไม่ใช่ขึ้นอยู่กับตัวข้อความเอง

ใช้ทำอะไรได้บ้าง

  • เตรียมข้อความภาษาไทยที่มีสระและวรรณยุกต์ลอยจากผู้ใช้ ให้แทรกลงใน JSON request ได้อย่างปลอดภัย
  • สร้างคำสั่งเชลล์ที่มีอาร์กิวเมนต์แบบไดนามิกโดยไม่เสี่ยงต่อการฉีดคำสั่ง (command injection)
  • Escape อักขระพิเศษก่อนนำข้อความไปใช้เป็นแพตเทิร์นตัวอักษรจริงในนิพจน์ปกติ

Escape ซ้อนสองชั้นในบริบทที่ซ้อนกัน

เมื่อข้อความผ่านสองบริบทติดต่อกัน — เช่น สตริงถูกฝังลงใน JSON แล้ว JSON นั้นถูกส่งต่อเป็นอาร์กิวเมนต์ของคำสั่งเชลล์ — ต้อง escape ตามลำดับที่ถูกต้อง: เริ่มจากบริบทชั้นใน (JSON) ก่อน แล้วจึงตามด้วยบริบทชั้นนอก (เชลล์) การสลับลำดับหรือข้ามขั้นตอนใดขั้นตอนหนึ่งไปเป็นสาเหตุทั่วไปที่ทำให้สตริงที่ "escape ถูกต้องแล้ว" ยังคงพังอยู่ในทางปฏิบัติ

ลองใช้เครื่องมือ