Unicode và bảng mã là những thứ hoàn toàn khác nhau, không liên quan đến nhau.
Unicode
Gán một ID số cho mỗi ký tự:
- 0x41 → A
- 0xE1 → á
- 0x414 → Д
Vì vậy, Unicode chỉ định số 0x41 cho A, 0xE1 cho á và 0x414 cho Д.
Ngay cả mũi tên nhỏ → tôi đã sử dụng cũng có số Unicode của nó, đó là 0x2192. Và ngay cả các biểu tượng cảm xúc cũng có số Unicode, 😂 là 0x1F602.
Bạn có thể tra cứu số Unicode của tất cả các ký tự trong bảng này . Đặc biệt, bạn có thể tìm thấy ba ký tự đầu tiên ở trên tại đây , mũi tên ở đây và biểu tượng cảm xúc tại đây .
Các số này được Unicode gán cho tất cả các ký tự được gọi là điểm mã .
Mục đích của tất cả điều này là cung cấp một phương tiện để tham chiếu rõ ràng đến từng ký tự. Ví dụ: nếu tôi đang nói về 😂, thay vì nói "bạn biết đấy, biểu tượng cảm xúc cười ra nước mắt này" , tôi chỉ có thể nói, mã Unicode điểm 0x1F602 . Dễ dàng hơn, phải không?
Lưu ý rằng các điểm mã Unicode thường được định dạng bằng dấu đứng đầu U+
, sau đó là giá trị số thập lục phân được đệm ít nhất 4 chữ số. Vì vậy, các ví dụ trên sẽ là U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602.
Điểm mã Unicode nằm trong khoảng từ U + 0000 đến U + 10FFFF. Đó là 1.114.112 số. 2048 trong số này được sử dụng để thay thế , do đó, vẫn còn 1.112.064. Điều này có nghĩa là, Unicode có thể gán một ID duy nhất (điểm mã) cho 1.112.064 ký tự riêng biệt. Không phải tất cả các điểm mã này đều được gán cho một ký tự và Unicode được mở rộng liên tục (ví dụ: khi các biểu tượng cảm xúc mới được giới thiệu).
Điều quan trọng cần nhớ là tất cả những gì Unicode làm là gán một ID số, được gọi là điểm mã, cho mỗi ký tự để dễ dàng tham khảo và rõ ràng.
Mã hóa
Ánh xạ các ký tự thành các mẫu bit.
Các mẫu bit này được sử dụng để biểu diễn các ký tự trong bộ nhớ máy tính hoặc trên đĩa.
Có nhiều bảng mã khác nhau bao gồm các tập con ký tự khác nhau. Trong thế giới nói tiếng Anh, các bảng mã phổ biến nhất là:
Maps 128 ký tự (điểm mã U + 0000 đến U + 007F) đến mẫu bit có độ dài 7.
Thí dụ:
Bạn có thể xem tất cả các ánh xạ trong bảng này .
Maps 191 ký tự (điểm mã U + 0020 đến U + 007E và U + 00A0 đến U + 00FF) để mẫu bit có độ dài 8.
Thí dụ:
- a → 01100001 (0x61)
- á → 11100001 (0xE1)
Bạn có thể xem tất cả các ánh xạ trong bảng này .
Maps 1.112.064 ký tự (tất cả hiện Unicode điểm code) để mô hình chút hoặc chiều dài 8, 16, 24 hoặc 32 bit (có nghĩa là, 1, 2, 3, hoặc 4 byte).
Thí dụ:
- a → 01100001 (0x61)
- á → 11000011 10100001 (0xC3 0xA1)
- ≠ → 11100010 10001001 10100000 (0xE2 0x89 0xA0)
- 😂 → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)
Cách UTF-8 mã hóa các ký tự thành chuỗi bit được mô tả rất tốt ở đây .
Unicode và mã hóa
Nhìn vào các ví dụ trên, có thể thấy rõ Unicode hữu ích như thế nào.
Ví dụ: nếu tôi là người Latin-1 và tôi muốn giải thích mã hóa của mình là á, tôi không cần phải nói:
"Tôi mã hóa rằng a bằng aigu (hoặc tuy nhiên bạn gọi thanh tăng đó) là 11100001"
Nhưng tôi chỉ có thể nói:
"Tôi mã hóa U + 00E1 là 11100001"
Và nếu tôi là UTF-8 , tôi có thể nói:
"Đến lượt tôi, tôi mã hóa U + 00E1 là 11000011 10100001"
Và mọi người rõ ràng là chúng tôi muốn nói đến nhân vật nào.
Bây giờ đến sự nhầm lẫn thường phát sinh
Đúng là đôi khi mẫu bit của bảng mã, nếu bạn hiểu nó là số nhị phân, giống với điểm mã Unicode của ký tự này.
Ví dụ:
- ASCII mã hóa a là 1100001, mà bạn có thể hiểu là số thập lục phân 0x61 và điểm mã Unicode của a là U + 0061 .
- Latin-1 mã hóa á là 11100001, mà bạn có thể hiểu là số thập lục phân 0xE1 và điểm mã Unicode của á là U + 00E1 .
Tất nhiên, điều này đã được sắp xếp như thế này nhằm mục đích thuận tiện. Nhưng bạn nên nhìn nó như một sự trùng hợp thuần túy . Mẫu bit được sử dụng để biểu diễn một ký tự trong bộ nhớ không bị ràng buộc theo bất kỳ cách nào với điểm mã Unicode của ký tự này.
Thậm chí không ai nói rằng bạn phải giải thích một chuỗi bit như 11100001 là một số nhị phân. Chỉ cần nhìn nó như là chuỗi các bit mà Latin-1 sử dụng để mã hóa ký tự á .
Quay lại câu hỏi của bạn
Mã hóa được sử dụng bởi trình thông dịch Python của bạn là UTF-8 .
Đây là những gì đang xảy ra trong các ví dụ của bạn:
ví dụ 1
Phần sau mã hóa ký tự á trong UTF-8. Điều này dẫn đến chuỗi bit 11000011 10100001, được lưu trong biến a
.
>>> a = 'á'
Khi bạn nhìn vào giá trị của a
, nội dung của nó 11000011 10100001 được định dạng là số hex 0xC3 0xA1 và xuất ra dưới dạng '\xc3\xa1'
:
>>> a
'\xc3\xa1'
Ví dụ 2
Phần sau lưu điểm mã Unicode của á, là U + 00E1, trong biến ua
(chúng tôi không biết Python sử dụng định dạng dữ liệu nào bên trong để đại diện cho điểm mã U + 00E1 trong bộ nhớ và nó không quan trọng đối với chúng tôi):
>>> ua = u'á'
Khi bạn nhìn vào giá trị của ua
, Python cho bạn biết rằng nó chứa điểm mã U + 00E1:
>>> ua
u'\xe1'
Ví dụ 3
Phần sau mã hóa điểm mã Unicode U + 00E1 (đại diện cho ký tự á) bằng UTF-8, dẫn đến mẫu bit 11000011 10100001. Một lần nữa, đối với đầu ra, mẫu bit này được biểu diễn dưới dạng số hex 0xC3 0xA1:
>>> ua.encode('utf-8')
'\xc3\xa1'
Ví dụ 4
Sau đây mã hóa điểm mã Unicode U + 00E1 (đại diện cho ký tự á) bằng chữ Latinh-1, kết quả là mẫu bit 11100001. Đối với đầu ra, mẫu bit này được biểu diễn dưới dạng số hex 0xE1, trùng hợp giống với mẫu ban đầu điểm mã U + 00E1:
>>> ua.encode('latin1')
'\xe1'
Không có mối quan hệ nào giữa đối tượng Unicode ua
và bảng mã Latin-1. Rằng điểm mã của á là U + 00E1 và mã hóa Latinh-1 của á là 0xE1 (nếu bạn giải thích mẫu bit của mã hóa là số nhị phân) là một sự trùng hợp thuần túy.
unicode
, nó chỉ là sự trừu tượng của ký tự unicode;unicode
có thể được chuyển đổi sangstr
một số mã hóa (ví dụutf-8
).