Tại sao UTF-8 lãng phí một số bit trong mã hóa của nó


16

Theo bài viết trên Wikipedia , UTF-8 có định dạng này:

Mã đầu tiên Mã cuối Byte Byte 1 Byte 2 Byte 3 Byte 4
điểm được sử dụng
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x có nghĩa là bit này được sử dụng để chọn điểm mã.

Điều này làm lãng phí hai bit trên mỗi byte tiếp tục và một bit trong byte đầu tiên. Tại sao UTF-8 không được mã hóa như sau?

Mã đầu tiên Mã cuối Byte Byte 1 Byte 2 Byte 3
điểm được sử dụng
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

Nó sẽ lưu một byte khi điểm mã nằm ngoài Mặt phẳng đa ngôn ngữ cơ bản hoặc nếu điểm mã nằm trong phạm vi [U + 800, U + 3FFF].

Tại sao UTF-8 không được mã hóa theo cách hiệu quả hơn?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt Mã hóa đề xuất của bạn tương tự như đề xuất FSS / UTF ban đầu. Ken Thompson và Rob Pike muốn tài sản tự đồng bộ hóa.
ninjalj

4
Ngoài ra, mã hóa của bạn dường như không đảm bảo rằng các giá trị mã ASCII không xuất hiện trong bất kỳ phần nào của biểu diễn cho các ký tự không phải ASCII. FSS / UTF và UTF-8 được thiết kế để hoạt động với các chương trình cũ, (ví dụ: những chương trình sử dụng ASCII NUL và dấu gạch chéo (dấu phân cách đường dẫn) làm dấu phân cách).
ninjalj

Câu trả lời:


25

Điều này được thực hiện để bạn có thể phát hiện khi bạn đang ở giữa một chuỗi nhiều byte. Khi xem dữ liệu UTF-8, bạn biết rằng nếu bạn thấy 10xxxxxx, bạn đang ở giữa một nhân vật đa nhân và nên sao lưu trong luồng cho đến khi bạn nhìn thấy 0xxxxxxhoặc 11xxxxxx. Sử dụng lược đồ của bạn, byte 2 hoặc 3 có thể dễ dàng kết thúc với các patters như 0xxxxxxxhoặc11xxxxxx

Ngoài ra, hãy nhớ rằng số tiền được lưu thay đổi hoàn toàn trên loại dữ liệu chuỗi bạn đang mã hóa. Đối với hầu hết văn bản, ngay cả văn bản châu Á, bạn sẽ hiếm khi thấy bốn ký tự byte với văn bản bình thường. Ngoài ra, ước tính ngây thơ của mọi người về cách văn bản sẽ trông thường sai. Tôi đã nhắn tin cho UTF-8 bao gồm các chuỗi tiếng Nhật, tiếng Trung và tiếng Hàn, nhưng thực ra tiếng Nga chiếm phần lớn không gian. (Bởi vì các chuỗi châu Á của chúng ta thường có các ký tự La Mã xen kẽ cho tên riêng, dấu câu và như vậy và vì từ tiếng Trung trung bình là 1-3 ký tự trong khi từ tiếng Nga trung bình là nhiều, nhiều hơn nữa.)


Nhưng với tôi lược đồ nếu bạn bắt đầu tại một địa điểm được biết là đang cầu xin một nhân vật, thì bạn có thể cho biết có bao nhiêu byte trong ký tự và đến việc cầu xin nhân vật tiếp theo.
qbt937

11
Chắc chắn rồi. Lược đồ của bạn dày đặc thông tin hơn nhưng không có tính năng quan trọng mà UTF-8 cung cấp. Nói chung, mọi người thích sự an toàn, đó là lý do tại sao UTF-8 có thể. Ngoài ra, để thực sự chứng minh chương trình của bạn thực sự hiệu quả hơn, bạn muốn cung cấp số liệu thống kê bằng văn bản thực. Bạn cũng có thể thấy rằng trong hầu hết các văn bản thực, lược đồ của bạn tiết kiệm được một khoản rất nhỏ và do đó khoản tiết kiệm không đáng là bao.
Gort Robot

3
Một đặc điểm quan trọng khác: Nếu không có mã số không được nhúng, thì không có số 0 được nhúng trong chuỗi.
Ded repeatator

Đối với tập lệnh tiếng Thái, bạn cần cho phép 4 byte cho mỗi ký tự được in. Họ không chỉ đến muộn trong bữa tiệc và do đó có một nhóm mã được đánh số cao. Nhiều thứ trông giống như một ký tự khi được in thực sự bao gồm ba ký tự unicode khác nhau.
James Anderson

@ qbt937: Sử dụng lược đồ của bạn, làm thế nào một người có thể quét nhanh để tìm hiểu xem một chuỗi có chứa chuỗi khác không?
supercat

6

Cách chính thức cho phép bộ giải mã biết khi nào nó ở giữa bộ dữ liệu và nó biết bỏ qua các byte (hoặc quay ngược) cho đến khi byte bắt đầu bằng 0hoặc 11; điều này ngăn giá trị rác khi một byte đơn bị hỏng.


3

Câu trả lời ngắn, đề xuất của bạn không phân biệt giữa byte đầu tiên và byte tiếp tục.

Mẫu bit ở đầu cao của byte đầu tiên cho bạn biết có bao nhiêu byte mà ký tự thực tế được tạo. Các mẫu này cũng cung cấp một số nhận dạng lỗi trong khi phân tích chuỗi. Nếu bạn đang đọc byte đầu tiên (dường như) của một ký tự và bạn nhận được 10xxxxxx thì bạn biết rằng bạn không đồng bộ.


2

Điều chưa được đề cập là nếu bạn có một chuỗi điểm mã chính xác và một con trỏ được đảm bảo để trỏ đến byte đầu tiên của điểm mã, với UTF-8, bạn có thể rất dễ dàng tìm thấy con trỏ đến byte đầu tiên của điểm mã trước đó (bỏ qua tất cả các byte bắt đầu bằng 01xx xxxx). Với mã hóa của bạn, không thể kiểm tra tất cả các byte cho đến khi bắt đầu chuỗi.

Hãy xem xét các chuỗi của (2n + 2) byte

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

Nếu bạn có một con trỏ tới byte đầu tiên của điểm mã đầu tiên sau chuỗi này, bạn phải kiểm tra tất cả các byte để tìm hiểu xem mã cuối cùng là 0xxxxxxx hay (10xxxxxx, 0xxxxxxx).

Thực tế, có các sơ đồ mã hóa hiệu quả hơn, trong đó việc đi đến điểm mã trước đó có thể được thực hiện trong thời gian không đổi và con trỏ đến giữa điểm mã có thể được sửa. Cho phép các mã sau:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

Nếu một trong ba byte trước đó là ≥ 236 thì đó là khởi đầu của chuỗi 3 byte, bởi vì không thể có hai byte như vậy trong bất kỳ chuỗi 3 byte hợp lệ nào. Mặt khác, nếu một trong hai byte trước là ≥ 128 thì đó là bắt đầu của chuỗi hai byte. Mặt khác, byte trước đó là một byte đơn <128.

Tìm kiếm một chuỗi con trở nên khó khăn hơn một chút. Bạn có thể muốn loại trừ các byte bằng 0 để một chuỗi chỉ chứa một byte bằng 0 nếu nó chứa một điểm mã bằng không.


Điều chưa được đề cập đến - không thực sự như điều này diễn ra trực tiếp từ quan sát được thực hiện trong câu trả lời của @ratchet freak.
Piotr Dobrogost
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.