Hướng dẫn sử dụng ký tự đặc biệt Unicode/Chương 2: Các bảng mã ký tự
Chương 2: Các bảng mã ký tự
[sửa]Chương này giới thiệu các phương thức mã hóa (encoding) được sử dụng để lưu trữ và truyền tải ký tự Unicode. Hiểu rõ các bảng mã giúp bạn xử lý văn bản chính xác và tránh lỗi hiển thị.
2.1 ASCII - Nền tảng của mọi bảng mã
[sửa]2.1.1 Giới thiệu ASCII
[sửa]ASCII (American Standard Code for Information Interchange) là bảng mã ký tự đầu tiên được chuẩn hóa, ra đời năm 1963.
Đặc điểm:
- Sử dụng 7 bit để biểu diễn mỗi ký tự
- Tổng cộng 128 ký tự (27 = 128)
- Tương thích với mọi hệ thống máy tính hiện đại
2.1.2 Cấu trúc bảng ASCII
[sửa]| Phạm vi | Loại ký tự | Ví dụ |
|---|---|---|
| 0–31 | Ký tự điều khiển | Tab (9), Enter (13), Escape (27) |
| 32–47 | Dấu câu và ký hiệu | Space (32), ! (33), " (34) |
| 48–57 | Chữ số | 0–9 |
| 65–90 | Chữ cái in hoa | A–Z |
| 97–122 | Chữ cái thường | a–z |
| 123–127 | Ký hiệu bổ sung | (124), } (125) |
Bảng ASCII đầy đủ (ký tự in được):
Dec Hex Ký tự Dec Hex Ký tự Dec Hex Ký tự
32 20 (space) 64 40 @ 96 60 `
33 21 ! 65 41 A 97 61 a
34 22 " 66 42 B 98 62 b
35 23 # 67 43 C 99 63 c
36 24 $ 68 44 D 100 64 d
37 25 % 69 45 E 101 65 e
38 26 & 70 46 F 102 66 f
39 27 ' 71 47 G 103 67 g
40 28 ( 72 48 H 104 68 h
41 29 ) 73 49 I 105 69 i
42 2A * 74 4A J 106 6A j
43 2B + 75 4B K 107 6B k
44 2C , 76 4C L 108 6C l
45 2D - 77 4D M 109 6D m
46 2E . 78 4E N 110 6E n
47 2F / 79 4F O 111 6F o
48 30 0 80 50 P 112 70 p
49 31 1 81 51 Q 113 71 q
50 32 2 82 52 R 114 72 r
51 33 3 83 53 S 115 73 s
52 34 4 84 54 T 116 74 t
53 35 5 85 55 U 117 75 u
54 36 6 86 56 V 118 76 v
55 37 7 87 57 W 119 77 w
56 38 8 88 58 X 120 78 x
57 39 9 89 59 Y 121 79 y
58 3A : 90 5A Z 122 7A z
59 3B ; 91 5B [ 123 7B {
60 3C < 92 5C \ 124 7C |
61 3D = 93 5D ] 125 7D }
62 3E > 94 5E ^ 126 7E ~
63 3F ? 95 5F _
2.1.3 Hạn chế của ASCII
[sửa]ASCII chỉ đủ cho tiếng Anh cơ bản, không hỗ trợ:
- Chữ cái có dấu (é, ñ, ü)
- Chữ viết không phải Latinh (Cyrillic, Hy Lạp, Ả Rập)
- Chữ tượng hình (Hán, Nhật, Hàn)
- Tiếng Việt với các dấu thanh
2.2 Các bảng mã mở rộng
[sửa]2.2.1 Extended ASCII (8-bit)
[sửa]Nhiều bảng mã mở rộng ASCII lên 8 bit (256 ký tự), giữ nguyên 128 ký tự đầu của ASCII và thêm 128 ký tự mới:
- ISO 8859-1 (Latin-1): Tây Âu (Pháp, Đức, Tây Ban Nha)
- ISO 8859-2 (Latin-2): Trung Âu (Ba Lan, Séc, Hungary)
- ISO 8859-5: Cyrillic (Nga)
- ISO 8859-6: Ả Rập
- Windows-1252: Phiên bản Microsoft của Latin-1
2.2.2 Các bảng mã tiếng Việt cũ
[sửa]Trước khi Unicode phổ biến, tiếng Việt sử dụng nhiều bảng mã không tương thích:
| Bảng mã | Đặc điểm | Sử dụng |
|---|---|---|
| TCVN3 (ABC) | 2 byte cho mỗi ký tự có dấu | Cơ quan nhà nước |
| VNI | Dùng ký tự đặc biệt cho dấu | Windows cũ |
| VISCII | Mã hóa 8-bit | Unix, Internet đầu |
| VPS | Tương tự VISCII | Macintosh |
💡 Lưu ý: Ngày nay, tất cả văn bản tiếng Việt nên sử dụng Unicode (UTF-8). Các bảng mã cũ chỉ còn gặp trong tài liệu lưu trữ.
2.3 UTF-8 - Tiêu chuẩn phổ biến nhất
[sửa]2.3.1 Giới thiệu UTF-8
[sửa]UTF-8 (Unicode Transformation Format - 8 bit) là phương thức mã hóa Unicode phổ biến nhất hiện nay, được phát minh bởi Ken Thompson và Rob Pike năm 1992.
Đặc điểm nổi bật:
- Mã hóa độ dài thay đổi (1-4 byte)
- Tương thích ngược với ASCII
- Tự đồng bộ (self-synchronizing)
- Không có vấn đề thứ tự byte (endianness)
2.3.2 Cách mã hóa UTF-8
[sửa]UTF-8 sử dụng 1 đến 4 byte tùy thuộc vào code point:
| Phạm vi code point | Số byte | Mẫu bit | Ví dụ |
|---|---|---|---|
| U+0000 – U+007F | 1 | 0xxxxxxx | A (U+0041) → 41 |
| U+0080 – U+07FF | 2 | 110xxxxx 10xxxxxx | é (U+00E9) → C3 A9 |
| U+0800 – U+FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx | 中 (U+4E2D) → E4 B8 AD |
| U+10000 – U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 😀 (U+1F600) → F0 9F 98 80 |
Ví dụ chi tiết - Mã hóa chữ "ă" (U+0103):
- Code point: U+0103 = 0000 0001 0000 0011 (nhị phân)
- Thuộc phạm vi U+0080 – U+07FF → dùng 2 byte
- Mẫu: 110xxxxx 10xxxxxx
- Điền bit: 11000100 10000011 = C4 83
2.3.3 Ưu điểm của UTF-8
[sửa]Tương thích ASCII:
- Văn bản ASCII thuần túy là UTF-8 hợp lệ
- Phần mềm cũ vẫn có thể xử lý phần ASCII
Hiệu quả lưu trữ:
- Tiếng Anh: 1 byte/ký tự (như ASCII)
- Tiếng Việt: 2-3 byte/ký tự
- Tiếng Trung/Nhật: 3 byte/ký tự
- Emoji: 4 byte/ký tự
Phát hiện lỗi:
- Cấu trúc byte rõ ràng giúp phát hiện dữ liệu hỏng
- Có thể khôi phục từ giữa chuỗi byte
2.3.4 UTF-8 trong thực tế
[sửa]Theo thống kê W3Techs (2024), UTF-8 chiếm hơn 98% các trang web. Nó là mã hóa mặc định cho:
- HTML5
- JSON
- XML (khuyến nghị)
- Nhiều ngôn ngữ lập trình (Python 3, Rust, Go)
- Git và các hệ thống quản lý mã nguồn
2.4 UTF-16 - Mã hóa 16-bit
[sửa]2.4.1 Giới thiệu UTF-16
[sửa]UTF-16 sử dụng đơn vị 16-bit (2 byte) làm đơn vị cơ bản. Ký tự trong BMP dùng 1 đơn vị (2 byte), ký tự ngoài BMP dùng 2 đơn vị (4 byte - surrogate pair).
2.4.2 Surrogate Pairs
[sửa]Ký tự có code point > U+FFFF được mã hóa bằng cặp surrogate:
- High surrogate: U+D800 – U+DBFF
- Low surrogate: U+DC00 – U+DFFF
Công thức chuyển đổi:
Cho code point CP (với CP > 0xFFFF):
- CP' = CP - 0x10000
- High surrogate = 0xD800 + (CP' >> 10)
- Low surrogate = 0xDC00 + (CP' & 0x3FF)
Ví dụ - Emoji 😀 (U+1F600):
- CP' = 0x1F600 - 0x10000 = 0xF600
- High = 0xD800 + (0xF600 >> 10) = 0xD800 + 0x3D = 0xD83D
- Low = 0xDC00 + (0xF600 & 0x3FF) = 0xDC00 + 0x200 = 0xDE00
- Kết quả: D83D DE00
2.4.3 UTF-16 BE và LE
[sửa]Do sử dụng đơn vị 16-bit, UTF-16 có vấn đề thứ tự byte:
- UTF-16 BE (Big Endian): Byte cao trước
- UTF-16 LE (Little Endian): Byte thấp trước
BOM (Byte Order Mark):
- U+FEFF ở đầu file để chỉ định thứ tự byte
- UTF-16 BE: FE FF
- UTF-16 LE: FF FE
2.4.4 Sử dụng UTF-16
[sửa]UTF-16 được dùng nội bộ trong:
- Windows (API và hệ thống file NTFS)
- Java (kiểu String)
- JavaScript (kiểu String)
- .NET Framework
2.5 UTF-32 - Mã hóa cố định
[sửa]2.5.1 Đặc điểm UTF-32
[sửa]UTF-32 sử dụng chính xác 4 byte cho mọi ký tự, cho phép ánh xạ trực tiếp 1-1 với code point.
Ưu điểm:
- Truy cập ký tự theo chỉ số O(1)
- Đơn giản để xử lý
Nhược điểm:
- Tốn bộ nhớ (4 byte cho mọi ký tự)
- Ít được sử dụng trong lưu trữ hoặc truyền tải
2.5.2 Sử dụng UTF-32
[sửa]UTF-32 chủ yếu dùng cho xử lý nội bộ khi cần thao tác từng ký tự:
- Python 3 (một số bản dựng)
- Một số thư viện xử lý văn bản
2.6 So sánh các phương thức mã hóa
[sửa]| Tiêu chí | UTF-8 | UTF-16 | UTF-32 |
|---|---|---|---|
| Kích thước đơn vị | 8 bit | 16 bit | 32 bit |
| Byte/ký tự | 1-4 | 2-4 | 4 |
| Tương thích ASCII | Có | Không | Không |
| Vấn đề endianness | Không | Có | Có |
| Hiệu quả cho tiếng Anh | Cao | Trung bình | Thấp |
| Hiệu quả cho CJK | Trung bình | Cao | Thấp |
| Phổ biến Web | Rất cao | Thấp | Rất thấp |
2.7 Chuyển đổi giữa các bảng mã
[sửa]2.7.1 Nguyên tắc chuyển đổi
[sửa]Khi chuyển đổi giữa các bảng mã:
- Giải mã (decode): Chuyển từ byte sang code point
- Mã hóa (encode): Chuyển từ code point sang byte
Lưu ý quan trọng:
- Không phải mọi byte sequence đều hợp lệ trong mọi encoding
- Chuyển đổi có thể mất dữ liệu nếu encoding đích không hỗ trợ ký tự
2.7.2 Ví dụ trong Python
[sửa]# Mã hóa chuỗi Unicode sang UTF-8
text = "Xin chào Việt Nam! 🇻🇳"
utf8_bytes = text.encode('utf-8')
print(utf8_bytes)
# b'Xin ch\xc3\xa0o Vi\xe1\xbb\x87t Nam! \xf0\x9f\x87\xbb\xf0\x9f\x87\xb3'
# Giải mã UTF-8 sang Unicode
decoded = utf8_bytes.decode('utf-8')
print(decoded)
# Xin chào Việt Nam! 🇻🇳
# Chuyển đổi UTF-8 sang UTF-16
utf16_bytes = text.encode('utf-16')
print(utf16_bytes.hex())
2.7.3 Xử lý lỗi mã hóa
[sửa]Khi gặp byte không hợp lệ, có các chiến lược xử lý:
- strict: Báo lỗi (mặc định)
- ignore: Bỏ qua ký tự lỗi
- replace: Thay bằng ký tự thay thế (thường là ?)
- backslashreplace: Thay bằng escape sequence
# Ví dụ xử lý lỗi
invalid_bytes = b'\x80\x81\x82'
print(invalid_bytes.decode('utf-8', errors='replace'))
# ���
print(invalid_bytes.decode('utf-8', errors='ignore'))
# (chuỗi rỗng)
2.8 Nhận dạng bảng mã
[sửa]2.8.1 Dựa vào BOM
[sửa]| BOM (hex) | Encoding |
|---|---|
| EF BB BF | UTF-8 |
| FE FF | UTF-16 BE |
| FF FE | UTF-16 LE |
| 00 00 FE FF | UTF-32 BE |
| FF FE 00 00 | UTF-32 LE |
2.8.2 Phát hiện tự động
[sửa]Khi không có BOM, có thể dùng các thư viện phát hiện encoding:
- Python: chardet, charset-normalizer
- JavaScript: jschardet
- Java: juniversalchardet
⚠️ Cảnh báo: Phát hiện tự động không phải lúc nào cũng chính xác 100%. Nên xác định encoding rõ ràng khi có thể.
Câu hỏi ôn tập
[sửa]- ASCII có bao nhiêu ký tự? Tại sao ASCII không đủ cho tiếng Việt?
- UTF-8 mã hóa chữ "ê" (U+00EA) thành bao nhiêu byte? Tính cụ thể.
- Tại sao UTF-8 phổ biến hơn UTF-16 trên Web?
- Surrogate pair là gì? Khi nào cần sử dụng?
- BOM có tác dụng gì? UTF-8 có cần BOM không?
Bài tập thực hành
[sửa]- Viết chương trình chuyển đổi một chuỗi tiếng Việt sang các dạng UTF-8, UTF-16 và in ra dãy byte.
- Tạo file văn bản với các encoding khác nhau và so sánh kích thước file.
- Viết hàm phát hiện encoding của một file dựa vào BOM.