ขนมปังกลมต้นฉบับกำลังจัดบัตรหลายความกว้างให้ขอบขวาตรงกันบนไม้บรรทัดโต๊ะทำงาน

Bun.stringWidth: จัดคอลัมน์ terminal ตามความกว้างที่มองเห็น ไม่ใช่จำนวนอักขระ

พี่โชว์Engineering

การเติมช่องว่างด้วย text.length ทำให้ตาราง CLI เหลื่อมเมื่อเจออักษรที่กินสองคอลัมน์หรือ combining mark ครับ Bun.stringWidth คำนวณความกว้างที่ terminal มองเห็น จึงเหมาะกับ progress table, logger และ TUI

function padCell(value: string, width: number): string {
  const missing = Math.max(0, width - Bun.stringWidth(value));
  return value + " ".repeat(missing);
}

if (Bun.stringWidth("hello") !== 5) throw new Error("ASCII width");
if (Bun.stringWidth("界") !== 2) throw new Error("wide glyph width");
if (Bun.stringWidth("e\u0301") !== 1) throw new Error("combining mark width");
if (Bun.stringWidth(padCell("界", 4)) !== 4) throw new Error("padding");

console.log("stringWidth checks passed");

เหมือนจัดหนังสือบนชั้น: จำนวนเล่มไม่บอกว่ากินพื้นที่กี่เซนติเมตร ตัวอักษรหนึ่ง code point อาจกว้างสองคอลัมน์ ขณะที่ grapheme หนึ่งตัวอาจประกอบจากหลาย code point แต่กินคอลัมน์เดียว

ขอบเขตที่ต้องกำหนด

ความกว้าง Unicode มีกรณี ambiguous ที่ terminal และ locale อาจแสดงต่างกัน รวมถึง emoji sequence บางชุด อย่าสัญญาว่าตารางจะตรงทุก emulator จาก test เพียงเครื่องเดียว หาก layout สำคัญให้ทดสอบ terminal เป้าหมายและมีโหมด plain output สำหรับ log ที่เครื่องอ่าน

stringWidth ช่วยคำนวณช่อง ไม่ได้ตัด string อย่างปลอดภัยตาม grapheme หากต้อง truncate ให้ใช้ segmenter ที่เข้าใจ grapheme แล้ววัดทีละส่วน มิฉะนั้นอาจตัดกลาง combining sequence

Recap

  • ใช้ความกว้างที่แสดงผลแทน .length
  • ทดสอบ ASCII, wide glyph และ combining mark
  • แยกการวัดจากการตัดข้อความ
  • มี plain format เมื่อ output ถูก parse โดยระบบอื่น