Site logo
Tác giả
  • avatar Nguyễn Đức Xinh
    Name
    Nguyễn Đức Xinh
    Twitter
Ngày xuất bản
Ngày xuất bản

Full-width vs Half-width Trong Tiếng Nhật: Zenkaku Và Hankaku Khác Nhau Thế Nào?

Full-width Và Half-width Là Gì?

  • 全角(Full-width / Zenkaku) là dạng ký tự có độ rộng đầy đủ, thường chiếm khoảng một ô ký tự trong hệ thống chữ Nhật.
  • 半角(Half-width / Hankaku) là dạng ký tự có độ rộng hẹp hơn, thường gặp ở các ký tự ASCII.

Đây là chủ đề quan trọng và dễ bị xử lý sai nhất khi làm việc với text tiếng Nhật trong phần mềm — cùng một ký tự có thể tồn tại ở cả hai dạng, nhìn khác nhau nhưng mang cùng một ý nghĩa, và việc chọn sai chiến lược xử lý (giữ nguyên hay convert) có thể gây ra hàng loạt bug về validation, search và lưu trữ dữ liệu.

Ví Dụ Trực Quan

ABC   →   ABC
123   →   123
abc   →   abc
ア    →   ア

Bảng So Sánh Chi Tiết

Đặc điểm Full-width (全角 / Zenkaku) Half-width (半角 / Hankaku)
Độ rộng hiển thị 1 ô ký tự Khoảng 1/2 ô ký tự
Dung lượng Thường là 2 bytes Thường là 1 byte
Chữ số(数字) 12345 12345
Chữ cái(英字) ABCDE ABCDE
Ký tự đặc biệt(記号) ()。、!?:; ().,!?:;
Katakana(カタカナ) サンプル サンプル
Hiragana(ひらがな) さんぷる
Kanji(漢字) 日本語
Space(スペース)  

(Cột "Dung lượng" phản ánh nguồn gốc lịch sử từ encoding cũ như JIS X 0201/Shift_JIS — trong UTF-8 hiện đại, cả full-width lẫn half-width Katakana đều chiếm 3 bytes, còn Latin/số half-width vẫn 1 byte và full-width Latin/số là 3 bytes.)

Ứng Dụng Thực Tế

  • Full-width: được dùng phổ biến khi soạn thảo văn bản tiếng Nhật thông thường (Hiragana, Kanji, Katakana chuẩn) để giữ sự đồng đều về khoảng cách hiển thị trên dòng — đây là lý do font tiếng Nhật thường được thiết kế theo lưới monospace toàn-độ-rộng.
  • Half-width: dùng cho bảng chữ cái tiếng Anh (A-Z, a-z) và số (0-9) trong lập trình hoặc nhập liệu theo chuẩn quốc tế — đây cũng là canonical form nên dùng cho mọi giá trị có ý nghĩa logic (số điện thoại, mã bưu điện, SKU).
  • Trường hợp đặc biệt: Half-width Katakana (アイウエオ) ít khi xuất hiện trong văn bản hàng ngày, nhưng đôi khi vẫn bắt buộc phải dùng khi điền tên chủ tài khoản (口座名義) tại một số hệ thống ngân hàng cũ (legacy) ở Nhật Bản — một ví dụ thực tế cho thấy quyết định "convert hay không" luôn phải theo yêu cầu của từng hệ thống cụ thể, không có chuẩn chung.

Bạn có thể chuyển đổi qua lại giữa hai định dạng này bằng các công cụ "Chuyển đổi Ký tự Bán giác / Toàn giác" (Hankaku ⇄ Zenkaku Converter) có sẵn online, ví dụ công cụ tại dencode.com.

Cách Sử Dụng Trong Web Application

Trong một web application phục vụ người dùng Nhật, Full-width và Half-width xuất hiện xuyên suốt UI: label form, input field, message validation, dữ liệu hiển thị trên table/list, và cả khi import/export dữ liệu. Một số vị trí điển hình cần lưu ý:

  • Form input: tên, địa chỉ, ghi chú — nơi user gõ trực tiếp qua IME và dễ lẫn full-width/half-width mà không để ý (xem phần "Vì sao người Nhật vẫn dùng cả hai" bên dưới).
  • Search box: user có thể gõ mã sản phẩm ở dạng full-width (do IME tự convert), trong khi dữ liệu lưu là half-width → cần normalize ở tầng search trước khi so khớp, nếu không sẽ ra kết quả "không tìm thấy" dù mã nhập đúng.
  • Import file (CSV/Excel): dữ liệu từ hệ thống khác (đặc biệt legacy) có thể toàn bộ là half-width hoặc trộn lẫn cả hai, cần chuẩn hoá ngay tại bước import, trước khi lưu vào database.
  • Hiển thị lại dữ liệu cho người khác xem (ví dụ tên khách hàng trên đơn hàng, hoá đơn): nếu tự ý convert ở tầng hiển thị, có thể cho ra kết quả khác với những gì người dùng gốc đã nhập, gây khó hiểu hoặc sai lệch chứng từ.

Nguyên tắc thực dụng: quyết định full-width/half-width không phải là một cấu hình toàn cục áp dụng cho cả ứng dụng, mà phải là một quyết định riêng cho từng field, được ghi rõ trong tài liệu requirement (xem phần "Nên Quy Định Input Như Thế Nào?" bên dưới).

Vì Sao Full-width Và Half-width Dễ Gây Bug?

Ba lý do khiến đây là nguồn bug phổ biến bậc nhất khi làm hệ thống cho thị trường Nhật:

  1. Nhìn giống nhau, nhưng là hai giá trị Unicode khác nhau. A (U+0041) và (U+FF21) là hai code point hoàn toàn khác nhau về mặt kỹ thuật. So sánh === trong code hay WHERE column = 'ABC' trong SQL sẽ trả về false/không khớp nếu một bên là full-width, dù mắt người nhìn thấy "giống hệt nhau".
  2. User không chủ động gõ — IME tự động convert. Khi đang gõ tiếng Nhật ở chế độ zenkaku, số/chữ Latin gõ xen kẽ có thể tự động bị convert thành full-width mà người dùng không hề nhận ra, khiến dữ liệu "bẩn" xuất hiện ngay từ bước nhập liệu, trước khi chạm tới bất kỳ dòng code nào.
  3. Không có tầng nào tự động enforce quy tắc này. Framework và database không tự biết field nào cần half-width, field nào không — nếu Developer không định nghĩa rõ ràng, validation sẽ bị bỏ sót, dẫn đến cùng một field tồn tại dữ liệu ở cả hai dạng, gây search miss, duplicate ảo, hoặc lỗi tính toán (parseInt("123") trả về NaN trong JavaScript).

Hệ quả thực tế thường gặp: khách hàng tìm không ra đơn hàng dù đã nhập đúng mã sản phẩm, hai bản ghi tưởng chừng trùng nhau nhưng thực ra là hai giá trị khác nhau (hoặc ngược lại, hai giá trị nghiệp vụ khác nhau bị hệ thống coi là trùng), và báo cáo thống kê sai lệch vì cùng một giá trị nghiệp vụ bị tách thành nhiều dòng khác nhau trong database.

Vì Sao Tồn Tại Cả Hai Định Dạng?

Full-width (zenkaku) và Half-width (hankaku) bắt nguồn từ thời kỳ máy tính Nhật Bản dùng font kích thước cố định: một ký tự Kanji/Kana cần chiều rộng gấp đôi ký tự Latin để hiển thị đẹp trên lưới monospace — đó là "full-width". Ngược lại, "half-width" tồn tại để tiết kiệm không gian hiển thị và tương thích với hệ thống cũ (terminal, POS, hệ thống bank/mainframe) vốn chỉ hỗ trợ character set 1-byte (JIS X 0201).

Vì Sao Người Nhật Vẫn Dùng Cả Hai Ngày Nay?

Vì thói quen gõ: khi IME đang ở chế độ "toàn角" (zenkaku input mode) để gõ Kanji/Hiragana, người dùng gõ số hoặc chữ Latin xen kẽ (ví dụ địa chỉ "東京都渋谷区1-2-3") và IME có thể tự động convert số/chữ đó thành full-width mà người dùng không để ý. Đây chính là nguồn gốc phổ biến nhất của lỗi nhập nhầm: user không cố ý gõ full-width, mà do IME auto-convert.

Khi Nào Nên Normalize (Convert Về Canonical Form)?

  • Các trường có ý nghĩa số học hoặc logic (số điện thoại, mã bưu điện, số lượng, giá tiền, ngày tháng) — luôn nên convert full-width digit → half-width trước khi validate/lưu, vì không convert sẽ khiến parseInt("123") cho kết quả sai hoặc NaN.
  • Các trường dùng để search/so khớp (mã sản phẩm, username, email) — nên normalize để tránh tình trạng hai user nhập cùng một mã nhưng ở hai dạng khác nhau (ABC123ABC123) bị coi là hai giá trị khác nhau.
  • Trường furigana yêu cầu Katakana — thường cần convert Hiragana ⇄ Katakana và Half-width Katakana → Full-width Katakana để đưa về một canonical form duy nhất trước khi lưu.

Khi Nào KHÔNG Nên Tự Động Normalize?

  • Các trường free text hiển thị nguyên văn (địa chỉ chi tiết, ghi chú, tên hiển thị) — nếu người dùng cố ý gõ ABC (ví dụ để nhấn mạnh hoặc theo phong cách trình bày riêng), tự động convert về ABC có thể làm sai lệch ý định hiển thị của họ, đặc biệt nếu dữ liệu này được in ra chứng từ pháp lý hoặc hiển thị lại y nguyên cho người dùng khác xem.
  • Nửa-rộng Katakana () không nên tự động convert hai chiều một cách tuỳ tiện — quyết định "convert sang chiều nào" (luôn về full-width, hay giữ nguyên như legacy data) phải dựa trên business rule của hệ thống, không phải một mặc định kỹ thuật áp dụng chung cho mọi field.

Có Nên Tự Động Convert Full-width ↔ Half-width?

Không có câu trả lời đúng chung cho mọi trường hợp — quyết định phải phụ thuộc vào ý nghĩa của field, không phải một rule kỹ thuật áp dụng đồng loạt:

  • Nên convert khi field có ý nghĩa số học/logic hoặc dùng để so khớp chính xác (số điện thoại, mã bưu điện, mã sản phẩm, email) — xem chi tiết ở phần "Khi Nào Nên Normalize" bên trên.
  • Không nên tự động convert khi field là nội dung hiển thị tự do mà người dùng có thể cố ý chọn cách trình bày riêng (tên hiển thị, ghi chú, địa chỉ chi tiết).
  • Luôn cần một quyết định rõ ràng, được document lại, thay vì để mỗi Developer tự xử lý theo thói quen riêng trên cùng một hệ thống — đây chính là lý do nên định nghĩa tường minh Input Restrictions(入力制限) ngay từ bước viết requirement, thay vì để Developer tự suy đoán khi code.

Nên Quy Định Input Như Thế Nào?

Một sai lầm phổ biến khi viết tài liệu requirement là chỉ ghi kiểu dữ liệu chung chung:

Input: String

Cách viết này không nói lên được: field có cho phép ký tự tiếng Nhật không, có cho phép full-width không, có cho phép ký tự đặc biệt không — khiến Developer phải tự đoán, và trên cùng một hệ thống, mỗi người có thể đoán một kiểu khác nhau.

Thay vào đó, nên định nghĩa rõ ràng Input Restrictions(入力制限) cho từng field, dùng ký hiệu (cho phép) / × (không cho phép) để tránh mọi hiểu nhầm.

Ví dụ với field thông thường (Latin/số):

Allow Input
- Letters: 〇
- Numbers: 〇
- Special Characters: ×
- Full-width: ×
- Half-width: 〇

Ví dụ với field tiếng Nhật:

Allow Input
- Japanese: 〇
- Kanji(漢字): 〇
- Hiragana(ひらがな): 〇
- Katakana(カタカナ): 〇
- Full-width(全角): 〇
- Half-width(半角): ×

Ví Dụ Theo Từng Field Thực Tế

氏名(Name)

Japanese: 〇
Kanji(漢字): 〇
Hiragana(ひらがな): 〇
Katakana(カタカナ): 〇
Full-width(全角): 〇
Half-width(半角): ×

電話番号(Phone Number)

Numbers(数字): 〇
Full-width(全角): ×
Half-width(半角): 〇

商品コード(Product Code)

Letters(英字): 〇
Numbers(数字): 〇
Special Characters(記号): -
Full-width(全角): ×
Half-width(半角): 〇

Với format này, Developer khi implement không cần đoán, còn QC khi viết test case cũng có sẵn danh sách chính xác để kiểm tra — mỗi dòng /× trong tài liệu requirement chính là một test case tiềm năng, không cần suy luận thêm.

Nguyên Tắc Cốt Lõi

Input số/mã có ý nghĩa logic → nên normalize; input hiển thị/tự do → cân nhắc kỹ trước khi normalize, và luôn phải có quyết định rõ ràng từ business, không phải Developer tự suy đoán.

Đây chỉ là một mảnh trong bức tranh lớn hơn về xử lý text tiếng Nhật trong phần mềm — bao gồm cả IME, Unicode normalization, validation design, và database charset/collation. Xem đầy đủ tại bài Xử Lý Văn Bản Tiếng Nhật Trong Phát Triển Phần Mềm.