เครื่องคำนวณความยาวของสตริง

เมื่อคุณวางข้อความเข้าไป เครื่องมือนี้จะแสดงความยาวของข้อความในสี่รูปแบบที่แตกต่างกัน ได้แก่ .length ในรูปแบบ JavaScript (หน่วยรหัส UTF-16), จุดรหัส Unicode, กลุ่มกราฟีม (สิ่งที่ผู้ใช้รับรู้ว่าเป็นตัวอักษรเดียว), และไบต์ UTF-8 (สิ่งที่คอลัมน์ในฐานข้อมูลของคุณเก็บจริง) ค่าเหล่านี้อาจไม่ตรงกันสำหรับข้อความที่มีอีโมจิ สัญลักษณ์ธง หรือเครื่องหมายรวมตัว และความไม่ตรงกันนี้เองคือสาเหตุของบั๊กจำนวนมาก

ความยาวของสตริงในสี่ความหมาย

  1. 1

    หน่วยรหัส UTF-16

    ค่าที่ `str.length` ส่งกลับในภาษา JavaScript โดยใช้ค่า 1 สำหรับตัวอักษรส่วนใหญ่ และค่า 2 สำหรับรหัสใดๆ ที่อยู่นอกเหนือจากชุด U+FFFF (เช่น อีโมจิ หรือตัวอักษรโบราณ)

  2. 2

    จุดรหัส (code points)

    หนึ่งจุดต่อสเกลาร์ยูนิโค้ดหนึ่งตัว อีโมจินับเป็น 1 ต่อหนึ่งตัว ส่วนลำดับ ZWJ นับได้หลายจุด

  3. 3

    กลุ่มกราฟีม (Grapheme clusters)

    สิ่งที่ผู้ใช้เรียกว่า “ตัวอักษรเดียว” นั้น โดย `🇺🇸` มีจำนวนจุดรหัส 2 แต่เป็นกราฟีมเพียงหนึ่งตัว ส่วน `n̈` ก็มีจำนวนจุดรหัส 2 เช่นกัน แต่ก็เป็นกราฟีมเพียงหนึ่งตัวเท่านั้น

  4. 4

    ไบต์ของ UTF-8

    ข้อมูลที่ฐานข้อมูลของคุณจัดเก็บ: ASCII = 1 ไบต์ต่อชุด; รูปแบบมาตรฐานของยุโรป = 2 ไบต์; CJK = 3 ไบต์; และอีโมจิส่วนใหญ่ = 4 ไบต์

ตัวอย่าง

สตริง ความยาวของสตริง (JS .length) จำนวนจุดในรหัส กราฟีม ไบต์ตามมาตรฐาน UTF-8
hello 5 5 5 5
café 4 4 4 5
😀 2 1 1 4
🇺🇸 4 2 1 8
👨‍👩‍👧 (ครอบครัว) 8 5 1 18
n̈ (n + เครื่องหมายสองจุดข้างบน) 2 2 1 3

ทำไมตัวเลขจึงแตกต่างกัน

สตริงใน JavaScript อยู่ในรูปแบบ UTF-16 ดังนั้นจุดรหัสที่สูงกว่า U+FFFF จะถูกจัดเก็บเป็นคู่แทน (surrogate pair) ซึ่งประกอบด้วยหน่วยรหัส UTF-16 สองตัว จึงทำให้ "😀".length === 2 ผู้ใช้มักไม่ชอบเรื่องนี้ เพราะพวกเขามองว่า 😀 เป็นตัวอักษรเพียงตัวเดียว

กราฟีมไปไกลกว่านั้นอีก ธงของประเทศประกอบด้วยจุดรหัสบ่งชี้ภูมิภาคสองจุด แต่ผู้ใช้มองเห็นเป็นธงเดียว เช่น "🇺🇸".length === 4 ใน JavaScript ซึ่งฟังดูไร้เหตุผล แต่ก็เป็นเช่นนั้นจริง หากต้องการวนซ้ำทีละกราฟีม ให้ใช้ Intl.Segmenter (แบบสมัยใหม่) หรือไลบรารี grapheme-splitter หรือจัดการเองด้วยมือ

ไบต์ UTF-8: สิ่งที่ฐานข้อมูลของคุณจัดเก็บ

สำหรับคอลัมน์ชนิด VARCHAR(255):

  • ใน MySQL utf8 (จริง ๆ คือ utf8mb3) ค่า 255 หมายถึงจำนวนไบต์ ส่วน café ใช้ 5 ไบต์ จึงเก็บได้ 51 ชุด
  • ใน MySQL utf8mb4 (UTF-8 จริงที่รวมอีโมจิ) ยังคงนับเป็นไบต์ แต่การเข้ารหัสรองรับลำดับยาว 4 ไบต์
  • ใน Postgres VARCHAR(255) ค่า 255 หมายถึงจำนวนตัวอักษร (จุดรหัส) ไม่ใช่ไบต์
  • ใน SQL Server VARCHAR ค่าจะต่างกันไปตามการเรียงลำดับ (collation) ส่วน NVARCHAR จะนับหน่วย UCS-2 ขนาด 2 ไบต์

หากคุณกำหนดขนาดฟิลด์ในฐานข้อมูลตามจำนวนตัวอักษรที่ผู้ใช้มองเห็น ให้ใช้ค่า “จำนวนไบต์ × 4” เพื่อความปลอดภัยในคอลัมน์ UTF-8 เพราะแต่ละกราฟีมอาจใช้พื้นที่ได้ถึง 4 ไบต์ต่อจุดรหัส และลำดับ ZWJ ยังเพิ่มขึ้นอีก

การนับตัวอักษรแบบ Twitter

Twitter นับทวีตตามกฎเฉพาะของตน คือนับเป็นจุดรหัส แต่อีโมจิและอักษรภาพ CJK จะนับเป็น 2 ทวีตที่เป็น ASCII ล้วนสามารถมีได้ถึง 280 ตัวอักษร ส่วนทวีตที่ใช้อีโมจิ 140 ตัวจะถึงเพดานที่ 140 “ตัวอักษร”

การนับ SMS: GSM 7 บิตได้ 160 ตัวอักษร หากมีตัวอักษรที่ไม่ใช่ GSM (เช่น á, é, ñ หรืออีโมจิ) แม้แต่ตัวเดียว การเข้ารหัสจะเปลี่ยนไปเป็น UCS-2 และความยาวข้อความจะลดลงเหลือ 70 ตัวอักษร

การใช้งานจริง

  • การกำหนดขนาดคอลัมน์ในฐานข้อมูล, ตรวจสอบจำนวนไบต์ก่อนเขียนสคริปต์ย้ายฐานข้อมูล (migration)
  • การบังคับใช้โควตา API, API ส่วนใหญ่นับเป็นไบต์ ไม่ใช่ตัวอักษร
  • การตรวจสอบฟอร์ม, แสดงจำนวนตัวอักษรที่ถูกต้องตรงกับความคาดหวังของผู้ใช้ (กราฟีม)
  • การดีบักประสิทธิภาพ, ทำไม regex นี้จึงวนซ้ำช้า? เพราะข้อมูลขาเข้ายาวกว่าในหน่วยรหัสถึง 3 เท่าเมื่อเทียบกับในหน่วยกราฟีม

คำถามที่พบบ่อย

อีโมจิตัวนี้เป็นลำดับ ZWJ ที่รวมจุดรหัสหลายจุดเข้าด้วยกัน (เช่น อีโมจิครอบครัวมีจุดรหัส 7 จุด) Twitter นับว่าเป็น 2 ตัวอักษรตามกฎน้ำหนักของ Unicode ขณะที่โปรแกรมแก้ไขข้อความของคุณแสดงเป็นกราฟีมเพียงตัวเดียว ทั้งสองวิธีถูกต้องในเชิงเทคนิค เพียงแต่วัดคนละสิ่งกัน

ในฐานข้อมูล UTF-8 เพื่อความปลอดภัย ควรเผื่อ 4 ไบต์ต่อหนึ่งตัวอักษรที่คาดไว้ ฟิลด์ที่รองรับ 100 ตัวอักษร (กราฟีม) ควรเป็น VARCHAR(400) ไบต์ หรือถ้าฐานข้อมูลนับเป็นตัวอักษรอย่าง Postgres ก็ใช้ VARCHAR(100) พร้อมกำหนดชุดอักขระ (charset) ให้เหมาะสม

ใน JavaScript ขึ้นอยู่กับรูปแบบการทำให้เป็นบรรทัดฐาน (normalization) รูปแบบ NFC ที่รวมกัน (U+00E1) มีความยาวเท่ากับ 1 ส่วนรูปแบบ NFD ที่แยกออก (U+0061 + U+0301) มีความยาวเท่ากับ 2 ตัวอักษรที่แสดงเหมือนกัน แต่ลำดับไบต์ต่างกัน

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

เครื่องมือที่เกี่ยวข้อง

เครื่องแปลงตัวเลขเป็นคำไทย

เขียนจำนวนไม่เกิน 18 หลักเป็นคำไทย หรือเขียนจำนวนบาทและสตางค์ตามค่าที่กรอกในเบราว์เซอร์ รองรับเลขอารบิกกับเลขไทยและไม่ปัดค่า

เครื่องมือสร้างตัวอักษรวงกลม

แปลงข้อความธรรมดาให้เป็นตัวอักษรวงกลม (Ⓐ Ⓑ Ⓒ) ที่คัดลอกแล้ววางลงในไบโอ Instagram, TikTok และ Discord ได้ มีทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กในวงกลม พร้อมตัวเลขในวงกลม โดยไม่ต้องใช้แอป

สัญลักษณ์ลูกศรสำหรับคัดลอก

คัดลอกลูกศร Unicode ที่ใช้บ่อยได้ในคลิกเดียว ทั้งแบบตรง สองเส้น ทแยง มีขอ วงกลม และสามเหลี่ยม สำหรับเอกสาร แชต และงานออกแบบ

สัญลักษณ์น้อยกว่าหรือเท่ากับ

คัดลอกสัญลักษณ์ ≤ และสัญลักษณ์เปรียบเทียบทางคณิตศาสตร์ที่เกี่ยวข้อง รวมถึง Unicode เอนทิตี HTML และการเขียน LaTeX สำหรับสเปรดชีต งานวิจัย และหน้าเว็บ

ตัวเข้ารหัสเอนทิตี HTML

แปลงอักขระ HTML ที่ต้องระวังห้าตัวเป็นเอนทิตีแบบคงที่ หรือถอดรหัสเอนทิตีเป็นข้อความในเบราว์เซอร์ของคุณ

เครื่องกำเนิดข้อความแบบวงกลม

แปลงข้อความธรรมดาเป็นอักขระ Unicode แบบวงกลม รูปแบบโครงร่าง เติม และวงกลมตัวเลขสำหรับประวัติโซเชียล แชท และเอกสาร

เครื่องมือนี้มีให้บริการในภาษาอื่น