Pemeriksaan Lebar Menyatakan String Aman untuk Dipotong. Ia Membelah Kanji Menjadi Dua.

Sebuah nama dimasukkan ke dalam tabel terminal dan keluar dalam keadaan rusak. Nama belakangnya adalah 𠮷田.

Karakter pertamanya bukanlah 吉 yang umum. Karakter tersebut adalah 𠮷 (U+20BB7). Ini adalah bentuk langka yang digunakan dalam nama keluarga Jepang yang asli. Tabel tersebut memotong sel agar sesuai dengan kolom. Hal ini meninggalkan karakter yang rusak.

Bug tersebut terletak pada satu baris kode. Itu adalah sebuah optimasi yang memutuskan bahwa sebuah string aman untuk dipotong berdasarkan indeks.

Sebuah string JavaScript memiliki tiga panjang yang berbeda: • Code units (.length): "𠮷".length adalah 2. • Code points: [..."𠮷"].length adalah 1. • Display width: 𠮷 memakan 2 kolom.

Untuk teks bahasa Inggris standar, angka-angka ini semuanya sama. Kebetulan ini membuat kode terlihat aman.

Karakter 𠮷 melanggar aturan ini. Ia memiliki 2 code units karena merupakan sebuah surrogate pair. Ia memiliki 2 kolom karena merupakan karakter lebar (wide character). Angkanya cocok (2 = 2), tetapi karena alasan yang berbeda.

Library cli-table3 menggunakan fast path: Jika panjang code unit sama dengan display width, maka potong string berdasarkan indeks.

Ini berhasil selama bertahun-tahun karena karakter Jepang umum seperti 漢 memiliki panjang 1 dan lebar 2. Mereka tidak pernah memicu fast path tersebut.

Fast path hanya terpicu untuk karakter langka seperti 𠮷 atau emoji. Karakter-karakter ini memiliki panjang 2 dan lebar 2. Kode tersebut mengira mereka adalah karakter satu unit yang sederhana. Kode tersebut memotongnya menjadi dua berdasarkan indeks. Hal ini meninggalkan sebuah surrogate yang sendirian. Inilah sebabnya terminal menampilkan kotak yang rusak.

Untuk memperbaikinya, Anda harus:

  • Melindungi fast path untuk mengecualikan surrogate pairs.
  • Melakukan trim berdasarkan code points, bukan code units.

Menggunakan Array.from(str) membantu karena ia melakukan iterasi berdasarkan code point. Ini memastikan Anda tidak pernah memotong karakter menjadi dua.

Pelajaran yang didapat sangat sederhana: Jangan pernah mengukur dengan satu unit dan memotong dengan unit yang lain. Jika Anda mengukur display width atau code points, Anda harus memotong menggunakan unit yang sama.

Uji kode Anda dengan karakter CJK Extension B atau emoji. ASCII tidak akan pernah mengungkap bug ini.

Source: https://dev.to/greymothjp/a-width-check-said-the-string-was-safe-to-cut-it-split-a-kanji-in-half-4hjk

Optional learning community: https://greymoth-jp.github.io/cjk-failure-corpus/