บทความ

SMS ภาษาไทยส่งได้กี่ตัวอักษร นับสระ วรรณยุกต์ และอีโมจิยังไง

ข้อความไทยหนึ่ง SMS ได้ 70 ตัว เกินแล้วเหลือส่วนละ 67 สระกับวรรณยุกต์นับแยก อีโมจิส่วนใหญ่นับ 2 โพสต์นี้ไล่ที่มาของตัวเลขพวกนี้ และวิธีนับในโค้ดให้ตรงกับที่ผู้ให้บริการคิดเครดิต

เผยแพร่
เวลาอ่าน
5 นาที
แท็ก
#Laravel#PHP#Tools

ข้อความที่ตาเห็นราว 70 ตัว ผู้ให้บริการนับได้ 79

อย่างตอนที่เราทำระบบส่ง SMS แจ้งคำสั่งซื้อให้ลูกค้า ทางลูกค้าส่งตัวอย่างข้อความมาจากหน้าจอของผู้ให้บริการ SMS ข้อความแรกอ่านด้วยตาแล้วดูราว 70 ตัว แต่ผู้ให้บริการนับได้ 79 ตัว และคิดเป็น 2 เครดิต ลูกค้าจึงอยากได้หน้าจอที่ทีมพิมพ์ข้อความแล้วเห็นเลยว่าจะใช้กี่เครดิต ก่อนกดส่งจริง

พอต้องทำหน้าจอนี้ เราก็ต้องนับให้ตรงกับที่ผู้ให้บริการนับ ซึ่งไม่ได้นับตัวอักษรแบบที่ตาเราเห็น ต้องเข้าใจก่อนว่า SMS เก็บข้อความยังไง

หนึ่ง SMS ได้ 140 ไบต์ ภาษาอังกฤษจึงได้ 160 ตัว ภาษาไทยได้ 70

SMS หนึ่งข้อความบรรจุข้อมูลได้ 140 ไบต์ จะได้กี่ตัวอักษรขึ้นกับว่าเข้ารหัสข้อความแบบไหน มีสองแบบที่ใช้กัน

  • GSM-7 ใช้ 7 บิตต่อตัว 140 ไบต์คือ 1,120 บิต จึงได้ 160 ตัว แต่มีตัวอักษรให้ใช้แค่ชุดเดียวตามมาตรฐาน GSM 03.38 คือภาษาอังกฤษ ตัวเลข สัญลักษณ์พื้นฐาน และอักษรยุโรปบางตัว
  • UCS-2 ใช้ 2 ไบต์ต่อตัว ได้ 70 ตัว แต่ใส่อักษรได้แทบทุกภาษา รวมทั้งภาษาไทยและอีโมจิ

ระบบเลือกการเข้ารหัสจากตัวอักษรทั้งข้อความ ถ้ามีตัวที่ GSM-7 ไม่รู้จักแม้แค่ตัวเดียว ทั้งข้อความจะกลายเป็น UCS-2 ข้อความภาษาไทยจึงได้ 70 ตัวเสมอ ต่อให้ส่วนใหญ่เป็นตัวเลขหรือภาษาอังกฤษก็ตาม

ข้อความภาษาอังกฤษล้วนก็โดนได้เหมือนกัน ตัวที่เจอบ่อยคือเครื่องหมาย ’ แบบโค้ง ที่ Word หรือคีย์บอร์ดมือถือใส่ให้แทน ' ตรง ๆ ข้อความ We’ll text you จึงเหลือข้อความละ 70 ตัว แทนที่จะได้ 160

ข้อความ การเข้ารหัส ได้ต่อข้อความ
Your OTP is 482913 GSM-7 160
We’ll text you soon UCS-2 เพราะมี ’ 70
รหัส OTP คือ 482913 UCS-2 เพราะมีภาษาไทย 70

สระและวรรณยุกต์นับแยกตัว

ภาษาไทยเก็บสระบน สระล่าง และวรรณยุกต์เป็นตัวอักษรของตัวเอง วางซ้อนบนพยัญชนะตอนแสดงผล ตาเราเห็นช่องเดียว แต่ SMS นับทุกตัว

  • ที่ ตาเห็นช่องเดียว นับ 3 ตัว คือ ท ี ่
  • น้ำ นับ 3 ตัว คือ น ้ ำ
  • กี่บาท นับ 6 ตัว

ประโยคที่มีวรรณยุกต์เยอะ ๆ จึงยาวกว่าที่เห็นได้เป็นสิบตัว ข้อความ 79 ตัวที่เล่าไว้ข้างบนก็มาจากเรื่องนี้ ตาเห็นราว 70 ตัว แต่สระกับวรรณยุกต์ทำให้ล้นไปเป็นข้อความที่สอง

อีโมจิส่วนใหญ่นับเป็น 2

UCS-2 เก็บอักษรได้ราว 65,000 ตัวแรกของ Unicode อีโมจิส่วนใหญ่อยู่เกินช่วงนั้น เลยต้องเก็บเป็นสองหน่วยต่อกัน เรียกว่า surrogate pair ผลคือ

อีโมจิ นับเป็น เพราะ
✅ ✨ ❤ 1 อยู่ในช่วงแรกของ Unicode
📦 🚚 😀 2 เป็น surrogate pair
🙏🏻 4 มือไหว้ 2 กับสีผิวอีก 2
🇹🇭 4 ธงคืออักษรสองตัวต่อกัน ตัวละ 2
👨‍👩‍👧 8 คนสามคน คนละ 2 กับตัวเชื่อมที่มองไม่เห็นอีก 2 ตัว

อีโมจิครอบครัวหนึ่งตัวจึงกินที่ 8 ตัว เกินหนึ่งในสิบของข้อความไทยไปแล้ว ถ้าข้อความใกล้ 70 ตัว อีโมจิตัวเดียวก็พอทำให้กลายเป็น 2 ข้อความ

เกิน 70 ตัวแล้ว เหลือส่วนละ 67

ข้อความที่ยาวกว่าหนึ่ง SMS ต้องแบ่งส่งหลายข้อความ แล้วให้โทรศัพท์ปลายทางต่อกลับเป็นข้อความเดียว ทุกส่วนจึงต้องมีส่วนหัว เรียกว่า UDH บอกว่าเป็นส่วนที่เท่าไรจากทั้งหมดกี่ส่วน ส่วนหัวนี้ยาว 6 ไบต์ เหลือที่ใส่ข้อความ 134 ไบต์

  • UCS-2 ได้ส่วนละ 67 ตัว (134 ÷ 2)
  • GSM-7 ได้ส่วนละ 153 ตัว เพราะส่วนหัวกินที่ไป 7 ตัว

ตัวที่ 71 จึงไม่ได้เพิ่มมาแค่ตัวเดียว ทั้งข้อความจะแบ่งใหม่เป็นส่วนละ 67

ภาษาไทย (UCS-2) จำนวน SMS ภาษาอังกฤษ (GSM-7) จำนวน SMS
1–70 ตัว 1 1–160 ตัว 1
71–134 ตัว 2 161–306 ตัว 2
135–201 ตัว 3 307–459 ตัว 3

ผู้ให้บริการคิดเครดิตตามจำนวน SMS คูณจำนวนเบอร์ผู้รับ ข้อความ 2 ส่วนส่งให้ลูกค้า 1,000 คน คือ 2,000 เครดิต ข้อความที่ตัดให้สั้นลงได้สองสามคำจึงประหยัดได้จริงเวลาส่งทีละมาก ๆ

ฝั่ง GSM-7 มีอีกเรื่องหนึ่ง ตัว ^ { } [ ] ~ \ | € อยู่ในตารางเสริมของ GSM-7 ต้องมีรหัสนำหน้าอีกหนึ่งตัว จึงนับตัวละ 2

นับในโค้ดให้ตรงกับที่ผู้ให้บริการนับ

ข้อความไทยนับแบบ UCS-2 คือนับเป็นหน่วย UTF-16 ฝั่ง JavaScript ทำง่าย เพราะ string.length นับแบบนี้อยู่แล้ว ส่วน PHP ต้องระวัง mb_strlen() นับเป็น code point อีโมจิ 📦 จึงได้ 1 แทนที่จะเป็น 2 ต้องแปลงเป็น UTF-16 ก่อนแล้วค่อยนับไบต์

const units = message.length; // 'ที่ 📦🙏🏻'.length === 10

const credits = units === 0 ? 0 : units <= 70 ? 1 : Math.ceil(units / 67);

โค้ดนี้พอสำหรับระบบที่ข้อความมีภาษาไทยเสมอ อย่างระบบที่เราทำ ข้อความแจ้งคำสั่งซื้อทุกแบบเป็นภาษาไทย เราจึงนับแบบ UCS-2 อย่างเดียว ถ้าระบบส่งภาษาอังกฤษล้วนด้วย ต้องเช็กก่อนว่าทุกตัวอยู่ในชุด GSM-7 ไหม แล้วค่อยเลือกว่าจะนับแบบ 160/153 หรือ 70/67 และนับตัวในตารางเสริมเป็น 2

ถ้าต้องให้ทั้งหน้าจอและฝั่งเซิร์ฟเวอร์นับ ให้ใช้สูตรเดียวกันทั้งสองฝั่ง และมี test คุมไว้ด้วยข้อความตัวอย่างที่มีวรรณยุกต์และอีโมจิ เพราะสองที่นี้แยกกันเพี้ยนได้ง่ายเวลามีคนแก้ฝั่งเดียว

ให้ทีมลองพิมพ์ก่อนส่งจริง

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

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

อ่านต่อ

ล่าสุด

ดูทั้งหมด →