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

Shift_JIS vs UTF-8: Xử lý lỗi encoding và mojibake khi làm việc với mã nguồn legacy

Vì sao text trong file COBOL, VB.NET bị hiển thị lỗi?

Khi mở file .pco, .vb hoặc .ini từ các hệ thống legacy (đặc biệt xuất xứ Nhật Bản), bạn có thể gặp hiện tượng ký tự bị biến dạng như:

�T�u�V�X�e���敪�@�FRZ0
�T�u�V�X�e�����@�@�F��v�h�^�e

Thay vì nội dung tiếng Nhật đúng nghĩa. Đây không phải do máy tính thiếu ngôn ngữ tiếng Nhật hay font. Nguyên nhân chính là sai encoding (mã hóa ký tự).

Encoding là gì và tại sao quan trọng?

Encoding (mã hóa ký tự) là quy tắc ánh xạ giữa bytes trong file và các ký tự hiển thị. Một dãy bytes giống nhau có thể tương ứng với nhiều chuỗi ký tự khác nhau tùy encoding được chọn.

Bytes (hex) Shift_JIS UTF-8
82 C0 82 B5 あさ (sáng) Mojibake
E3 81 82 Mojibake

Khi editor dùng sai encoding để đọc file, bytes bị giải mã sai → mojibake (文字化け) — ký tự vỡ hình.

Các encoding phổ biến trong development

Shift_JIS (CP932)

  • Shift_JIS là encoding chuẩn của Windows tại Nhật Bản (code page 932).
  • Dùng rộng rãi trong hệ thống legacy: COBOL, VB6, VB.NET, mainframe.
  • Ưu điểm: tương thích tốt với Windows cũ, ít bytes hơn UTF-8 cho tiếng Nhật.
  • Nhược điểm: không chuẩn quốc tế, khó trao đổi với hệ thống đa ngôn ngữ.

UTF-8

  • UTF-8 là encoding chuẩn trên web và phần mềm hiện đại.
  • Hỗ trợ mọi ngôn ngữ trong một bảng mã.
  • Được dùng mặc định trong Git, GitHub, VSCode, Cursor.
  • Hầu hết file mới được tạo bằng UTF-8.

So sánh encoding

Tiêu chí Shift_JIS (CP932) UTF-8
Phạm vi ký tự Tiếng Nhật, Latin Toàn bộ Unicode
Bytes/ký tự (Hiragana) 2 bytes 3 bytes
Bytes/ký tự (ASCII) 1 byte 1 byte
Môi trường Windows JP, legacy Web, modern tools
BOM Không chuẩn Optional (UTF-8 BOM)
Khả năng tương thích Giảm dần Tăng mạnh

Nguyên nhân mojibake trong thực tế

Kịch bản điển hình

  1. File được lưu bằng Shift_JIS (ví dụ: program.pco, MainModule.vb).
  2. Editor (Cursor, VSCode) mặc định mở file bằng UTF-8.
  3. Bytes Shift_JIS bị giải mã như UTF-8 → ký tự hiển thị sai.

Ví dụ cụ thể

Comment trong file COBOL:

Nội dung đúng (Shift_JIS):

*     サブシステム区分   : XX
*     サブシステム名     : 会計システム
*     プログラムID     : PG001
*     プログラム名       : データチェック

Khi mở sai (UTF-8):

*     �T�u�V�X�e���敪�@�FXX
*     �T�u�V�X�e�����@�@�F����V�X�e
*     �v���O�����h�c�@�@�FPG001
*     �v���O�������@�@�@�F�f�[�^�`�F�b�N

Cách fix mojibake trong Cursor / VSCode

Bước 1: Mở lại file với encoding đúng

  1. Click encoding hiện tại (ví dụ UTF-8) ở thanh trạng thái góc dưới phải.
  2. Chọn "Reopen with Encoding".
  3. Chọn "Japanese (Shift JIS)" hoặc nhập 932 / shiftjis.
  4. File sẽ hiển thị đúng tiếng Nhật.

Bước 2: Lưu file sang UTF-8 (khuyến nghị)

Sau khi thấy nội dung đúng:

  1. Click encoding → "Save with Encoding".
  2. Chọn "UTF-8".
  3. File được chuyển sang UTF-8, phù hợp cho Git và công cụ hiện đại.

Bước 3: Cấu hình encoding mặc định cho project

Thêm file .vscode/settings.json:

{
  "files.encoding": "shiftjis",
  "files.autoGuessEncoding": true
}
  • files.encoding: encoding mặc định khi mở file mới.
  • files.autoGuessEncoding: tự đo encoding (có thể không chính xác với file nhỏ).

Lưu ý: Với project legacy toàn Shift_JIS, nên đặt "shiftjis". Với project mới hoặc hỗn hợp, dùng "utf8" và chỉ áp dụng Shift_JIS khi cần.

Bước 4: Xử lý file theo loại nội dung

Một số loại file cần xử lý riêng:

Loại file Encoding thường gặp Ghi chú
.pco, .COB, .CBL Shift_JIS Pro*COBOL, mainframe
.vb Shift_JIS VB.NET legacy
.ini Shift_JIS Config Windows JP
.xml Shift_JIS hoặc UTF-8 Kiểm tra declaration
Message.XML Shift_JIS Message resource
config.xml Shift_JIS DB / app config

Với file XML, kiểm tra dòng đầu:

<?xml version="1.0" encoding="Shift_JIS"?>

Nếu thấy encoding="Shift_JIS" hoặc encoding="Windows-31J", file đang dùng CP932.

EUC-JP và các encoding Nhật khác

Ngoài Shift_JIS, bạn có thể gặp EUC-JP (Unix/Linux Nhật) hoặc ISO-2022-JP (email):

Encoding Môi trường Đặc điểm
Shift_JIS (CP932) Windows JP Phổ biến nhất trong legacy
EUC-JP Unix, Linux JP Server, mainframe
ISO-2022-JP Email Escape sequences
UTF-8 Hiện đại Unicode chuẩn

Khi mojibake vẫn sai sau khi thử Shift_JIS, thử lần lượt EUC-JP và ISO-2022-JP. Tool file (Unix) hoặc chardet (Python) có thể hỗ trợ phát hiện:

import chardet
with open('program.pco', 'rb') as f:
    result = chardet.detect(f.read())
print(result)  # {'encoding': 'SHIFT_JIS', 'confidence': 0.99}

Case study: Dự án migration legacy

Trong nhiều dự án migration VB.NET + COBOL xuất xứ Nhật Bản, toàn bộ source thường dùng Shift_JIS (codepage 932):

  • VB.NET: Hàng trăm file .vb, config .xml, .ini
  • COBOL: Nhiều file .pco, file COPY .COB, .CBL
  • Ghi chú: Tài liệu deploy hoặc README thường ghi rõ encoding

Khi developer mở bằng Cursor/VSCode mặc định UTF-8, comment và message tiếng Nhật hiển thị mojibake. Giải pháp thường áp dụng:

  1. Thêm .vscode/settings.json với "files.encoding": "shiftjis" cho thư mục source.
  2. Ghi chú encoding trong tài liệu project.
  3. File mới (Markdown, config mới): dùng UTF-8.
  4. File legacy: mở đúng Shift_JIS, cân nhắc convert khi migrate.

Các tool hỗ trợ encoding

iconv (command line)

Chuyển encoding qua terminal:

# Shift_JIS → UTF-8
iconv -f SHIFT_JIS -t UTF-8 input.pco > output_utf8.pco

# UTF-8 → Shift_JIS
iconv -f UTF-8 -t SHIFT_JIS input_utf8.pco > output_sjis.pco

PowerShell (Windows)

# Đọc file Shift_JIS
$content = Get-Content -Path "program.pco" -Encoding Default

# Ghi sang UTF-8
$content | Out-File -FilePath "program_utf8.pco" -Encoding UTF8

Python script

# convert_encoding.py
def convert_file(input_path, output_path, from_enc='shift_jis', to_enc='utf-8'):
    with open(input_path, 'r', encoding=from_enc) as f:
        content = f.read()
    with open(output_path, 'w', encoding=to_enc) as f:
        f.write(content)

convert_file('program.pco', 'program_utf8.pco')

Chiến lược cho legacy codebase

Option 1: Giữ nguyên Shift_JIS

Phù hợp khi:

  • Không muốn sửa nhiều file.
  • Build/deploy vẫn dựa trên Shift_JIS.
  • Có tool/IDE hỗ trợ tốt encoding.

Cấu hình editor:

{
  "files.encoding": "shiftjis"
}

Option 2: Chuyển sang UTF-8

Phù hợp khi:

  • Muốn chuẩn hóa theo UTF-8.
  • Dùng Git, CI/CD, cloud.
  • Làm việc đội ngũ đa quốc gia.

Quy trình:

  1. Convert từng file: iconv hoặc "Save with Encoding".
  2. Đảm bảo build vẫn chạy (compiler hỗ trợ UTF-8).
  3. Cập nhật .gitattributes nếu cần.
  4. Thông báo cho team về thay đổi encoding.

Option 3: Hỗn hợp (hybrid)

  • File mới: UTF-8.
  • File legacy: Shift_JIS cho đến khi convert.
  • Dùng files.autoGuessEncoding và kiểm tra từng file quan trọng.

.gitattributes và encoding

Để Git xử lý encoding đúng:

# Legacy files - treat as binary or specify encoding
*.pco diff=cobol
*.vb text working-tree-encoding=UTF-8

# Nếu vẫn dùng Shift_JIS
*.pco working-tree-encoding=Shift_JIS

Lưu ý: Chuyển encoding có thể gây thay đổi lớn trong diff. Nên tách commit "convert encoding" riêng khỏi commit logic.

Checklist khi gặp mojibake

  • [ ] Xác nhận encoding gốc của file (Shift_JIS, EUC-JP, UTF-8).
  • [ ] Thử "Reopen with Encoding" với encoding phù hợp.
  • [ ] Xác nhận nội dung hiển thị đúng.
  • [ ] Quyết định: giữ encoding cũ hay convert sang UTF-8.
  • [ ] Nếu convert: dùng "Save with Encoding" hoặc iconv.
  • [ ] Cập nhật settings.json cho project nếu cần.
  • [ ] Test build và chạy ứng dụng sau khi đổi encoding.
  • [ ] Cập nhật tài liệu/README về encoding trong project.

UTF-8 BOM: Khi nào cần?

BOM (Byte Order Mark) là chuỗi bytes đặc biệt ở đầu file để đánh dấu encoding. Với UTF-8:

  • UTF-8 BOM: EF BB BF — một số tool Windows yêu cầu.
  • UTF-8 không BOM: Chuẩn trên web, Git, nhiều compiler.
Ngữ cảnh Khuyến nghị
Web, API, JSON UTF-8 không BOM
Batch script Windows UTF-8 BOM hoặc ANSI
C#, VB.NET source Thường UTF-8 không BOM
Excel CSV xuất từ JP Shift_JIS hoặc UTF-8 BOM

Trong Cursor/VSCode, "Save with Encoding" cho phép chọn "UTF-8 with BOM" hoặc "UTF-8" (không BOM). Với source code, ưu tiên UTF-8 không BOM.

Ảnh hưởng tới build và runtime

Compiler COBOL (Pro*COBOL)

Pro*COBOL thường nhận source theo encoding hệ điều hành. Trên Windows JP, mặc định là Shift_JIS. Nếu convert file sang UTF-8, cần kiểm tra compiler có hỗ trợ NCHARSET(UTF8) hoặc tương đương hay không.

VB.NET / MSBuild

VB.NET và MSBuild hỗ trợ nhiều encoding. File .vb UTF-8 thường build ổn. Với *.resx, cẩn thận khi đổi encoding vì có thể ảnh hưởng resource.

Database và config

File config như App.config, *.xml đọc bởi runtime .NET — cần encoding khớp với cách load. XmlDocument/XDocument có thể chỉ định encoding khi đọc file.

FAQ: Câu hỏi thường gặp

Q: Có cần cài Japanese language pack không?
A: Không bắt buộc. Mojibake do sai encoding, không phải thiếu font hay ngôn ngữ. Font như "MS Gothic", "Yu Gothic" thường có sẵn hoặc cài qua OS.

Q: Convert sang UTF-8 có làm hỏng file không?
A: Không, nếu convert đúng. Luôn backup trước khi convert hàng loạt.

Q: Git diff toàn thay đổi encoding thấy rối?
A: Nên tách commit: một commit chỉ convert encoding, commit khác chứa thay đổi logic. Dùng git diff -w để tạm bỏ qua thay đổi whitespace khi review.

Q: Làm sao biết file đang dùng encoding gì?
A: Thử "Reopen with Encoding" — nếu chọn đúng, text hiển thị rõ. Hoặc dùng file -i, chardet (Python).

Q: macOS/Linux có iconv không?
A: Có. Trên Windows có thể dùng WSL, Git Bash, hoặc PowerShell như ví dụ trên.

Troubleshooting: Một số lỗi thường gặp

Lỗi: "Unable to decode"

Editor không nhận ra encoding. Thử lần lượt: Shift_JIS, EUC-JP, Windows-1252 (cho Latin), UTF-8.

Lỗi: Một phần đúng, một phần sai

File có thể mixed encoding (ví dụ ASCII + Shift_JIS). Cần mở bằng hex editor, xác định vị trí chuyển encoding và xử lý thủ công hoặc script.

Lỗi: Sau khi convert, build fail

Compiler hoặc runtime vẫn expect encoding cũ. Kiểm tra tài liệu compiler, hoặc giữ encoding gốc cho đến khi tool hỗ trợ UTF-8.

Lỗi: Tiếng Nhật hiển thị vuông hoặc ?

Thiếu font hỗ trợ CJK. Cài font tiếng Nhật (MS Gothic, Yu Gothic, Noto Sans JP) cho OS và IDE.

Tổng kết

Mojibake xuất hiện khi file dùng encoding khác với encoding editor đang dùng. Với mã nguồn legacy tiếng Nhật (COBOL, VB.NET), thường gặp Shift_JIS bị mở bằng UTF-8.

Cách xử lý nhanh:

  1. Reopen with Encoding → chọn Shift_JIS (CP932).
  2. Save with Encoding → UTF-8 (nếu muốn chuẩn hóa).
  3. Cấu hình .vscode/settings.json cho project.

Best practice: Hướng tới UTF-8 cho mọi file mới; legacy file có thể convert dần khi có điều kiện. Luôn kiểm tra build và runtime sau khi đổi encoding. Ghi chú encoding trong README hoặc tài liệu project để đồng đội không gặp mojibake khi mở file lần đầu.