Số byte tối đa cho một ký tự được mã hóa UTF-8 là bao nhiêu?


79

Số byte tối đa cho một ký tự được mã hóa UTF-8 là bao nhiêu?

Tôi sẽ mã hóa các byte của một Chuỗi được mã hóa bằng UTF-8 và do đó cần có khả năng tính ra số byte tối đa cho một Chuỗi được mã hóa UTF-8.

Ai đó có thể xác nhận số byte tối đa cho một ký tự được mã hóa UTF-8 không


1
Trước tiên, bạn đã xem các tài nguyên thông thường, chẳng hạn như Bài báo UTF-8 của Wikipedia ... phải không?

5
Tôi đọc một số điều đó đã cho câu trả lời hỗn hợp ... Tôi thực sự có cảm giác câu trả lời được 3 vì vậy tôi rất vui vì tôi hỏi
Edd

2
Tôi sẽ để lại một liên kết youtube ở đây, có các Nhân vật, Biểu tượng, Phép màu Unicode của Tom Scott: goo.gl/sUr1Hf . Bạn có thể nghe và xem mọi thứ đang được phát triển như thế nào từ mã hóa ký tự ASCII sang utf-8.
Roy Lee,

Câu trả lời:


86

Số byte tối đa cho mỗi ký tự là 4 theo RFC3629 giới hạn bảng ký tự là U+10FFFF:

Trong UTF-8, các ký tự từ phạm vi U + 0000..U + 10FFFF (phạm vi có thể truy cập UTF-16) được mã hóa bằng cách sử dụng chuỗi từ 1 đến 4 octet.

(Đặc điểm kỹ thuật gốc cho phép tối đa sáu mã ký tự byte cho các điểm mã đã qua U+10FFFF.)

Các ký tự có mã nhỏ hơn 128 sẽ chỉ yêu cầu 1 byte và mã 1920 ký tự tiếp theo chỉ yêu cầu 2 byte. Trừ khi bạn đang làm việc với một ngôn ngữ bí truyền, nhân số ký tự với 4 sẽ là một đánh giá quá cao đáng kể.


7
Đối với bạn "ngôn ngữ bí truyền" là gì? Bất kỳ ngôn ngữ nào tồn tại trong thế giới thực hoặc một văn bản chuyển đổi giữa các ngôn ngữ khác nhau trên thế giới? Nhà phát triển hàm UTF-8-to-String có nên chọn 2, 3 hoặc 4 làm bộ nhân nếu anh ta thực hiện phân bổ quá mức và giảm kích thước kết quả sau khi chuyển đổi thực tế?
Daniel Marschall

1
@rinntech theo 'ngôn ngữ bí truyền', anh ấy có nghĩa là một ngôn ngữ có nhiều ký tự unicode giá trị cao (thứ gì đó ở gần cuối danh sách này: unicode-table.com/en/section ). Nếu bạn phải phân bổ quá mức, hãy chọn 4. Bạn có thể thực hiện chuyển đổi kép, một để xem bạn sẽ cần bao nhiêu byte và phân bổ, sau đó một chuyển đổi khác để thực hiện mã hóa; điều đó có thể tốt hơn việc phân bổ ~ 4 lần RAM cần thiết.
matiu

9
Luôn cố gắng xử lý trường hợp xấu nhất: hacker9.com/single-message-can-crash-whatsapp.html
Evgen Bodunov

20
Các ký tự CJKV chủ yếu chiếm 3 byte (với một số ký tự cổ / hiếm có 4 byte) và gọi chúng là bí truyền là một chút căng thẳng (chỉ riêng Trung Quốc đã chiếm gần 20% dân số thế giới ...).
Tgr

3
Tại sao nó bị giới hạn ở 4 trong khi trước đây là 6? Điều gì ngăn chúng ta tiếp tục tiêu chuẩn và có một byte dẫn đầu 11111111và có một 2^(6*7)khoảng trống cho các ký tự?
Aaron Franke,

32

Nếu không có ngữ cảnh khác, tôi sẽ nói rằng số byte tối đa cho một ký tự trong UTF-8 là

câu trả lời: 6 byte

Tác giả của câu trả lời được chấp nhận đã chỉ ra một cách chính xác đây là "đặc điểm kỹ thuật gốc". Điều đó hợp lệ thông qua RFC-2279 1 . Như J. Cocoe đã chỉ ra trong các nhận xét bên dưới, điều này đã thay đổi vào năm 2003 với RFC-3629 2 , giới hạn UTF-8 ở chế độ mã hóa 21 bit, có thể được xử lý bằng sơ đồ mã hóa sử dụng bốn byte.

trả lời nếu bao gồm tất cả unicode: 4 byte

Tuy nhiên, trong Java <= v7 , họ nói về tối đa 3 byte để biểu diễn unicode với UTF-8? Đó là bởi vì đặc điểm kỹ thuật unicode ban đầu chỉ xác định mặt phẳng đa ngôn ngữ cơ bản ( BMP ), tức là nó là phiên bản cũ hơn của unicode, hoặc tập hợp con của unicode hiện đại. Vì thế

trả lời nếu chỉ đại diện cho unicode gốc, BMP: 3 byte

Tuy nhiên, OP nói về việc đi theo hướng khác. Không phải từ ký tự thành UTF-8 byte, mà từ UTF-8 byte thành biểu diễn "Chuỗi" byte. Có lẽ tác giả của câu trả lời được chấp nhận đã hiểu điều đó từ ngữ cảnh của câu hỏi, nhưng điều này không nhất thiết phải rõ ràng, vì vậy có thể gây nhầm lẫn cho người đọc bình thường của câu hỏi này.

Đi từ UTF-8 sang mã hóa gốc, chúng ta phải xem cách triển khai "Chuỗi". Một số ngôn ngữ, như Python> = 3 sẽ đại diện cho mỗi ký tự bằng các điểm mã số nguyên, cho phép 4 byte cho mỗi ký tự = 32 bit để bao gồm 21 mà chúng ta cần cho unicode, với một số lãng phí. Tại sao không chính xác là 21 bit? Bởi vì mọi thứ nhanh hơn khi chúng được căn chỉnh theo byte. Một số ngôn ngữ như Python <= 2 và Java biểu diễn các ký tự bằng cách sử dụng mã hóa UTF-16, có nghĩa là chúng phải sử dụng các cặp thay thế để đại diện cho unicode mở rộng (không phải BMP). Dù bằng cách nào thì đó vẫn là tối đa 4 byte.

trả lời nếu đi UTF-8 -> mã hóa gốc: 4 byte

Vì vậy, kết luận cuối cùng, 4 là câu trả lời đúng phổ biến nhất, vì vậy chúng tôi đã đúng. Tuy nhiên, số dặm có thể thay đổi.


5
"đây vẫn là thông số kỹ thuật hiện tại và chính xác, theo wikipedia" - không còn nữa. Ngay sau khi bạn viết bài này (chỉnh sửa ngày 2 tháng 4), bài viết UTF-8 của Wikipedia đã được thay đổi để làm rõ rằng phiên bản 6-octet không phải là một phần của thông số UTF-8 (2003) hiện tại.
J. Cocoe

"Nhưng, trong Java <= v7, họ nói về tối đa 3 byte để biểu diễn unicode với UTF-8? Đó là bởi vì đặc tả unicode ban đầu chỉ xác định mặt phẳng đa ngôn ngữ cơ bản" - Đó có thể là lý do ban đầu, nhưng nó không phải là toàn bộ câu chuyện. Java sử dụng "UTF-8 đã được sửa đổi" và một trong những sửa đổi là nó "sử dụng định dạng hai lần ba byte của chính nó" thay vì "định dạng bốn byte của UTF-8 tiêu chuẩn" (từ của họ).
J. Cocoe

1
Không có điểm mã nào được phân bổ trên giới hạn 10FFFF (chỉ hơn một triệu) và nhiều triển khai UTF8 không bao giờ triển khai các trình tự dài hơn 4 byte (và một số chỉ 3, ví dụ như MySQL), vì vậy tôi sẽ coi là an toàn khi giới hạn cứng ở 4 byte cho mỗi codepoint ngay cả khi xem xét khả năng tương thích với các triển khai cũ hơn. Bạn chỉ cần đảm bảo rằng bạn loại bỏ bất kỳ thứ gì không hợp lệ trên đường vào. Lưu ý rằng khuyến nghị phân bổ sau khi tính toán độ dài byte chính xác của matiu là một cách tốt nếu có thể.
thomasrutter

2
"... [U] nicode có thể đại diện cho tối đa x10FFFF điểm mã. Vì vậy, bao gồm cả 0, điều đó có nghĩa là chúng ta có thể làm điều đó với các byte này: F FF FF, tức là hai byte rưỡi, hoặc 20 bit." Tôi tin rằng điều này là một chút không chính xác. Số điểm mã từ 0x0 đến 0x10FFFF sẽ là 0x110000, có thể được biểu diễn bằng 1F FF FFhoặc 21 bit. Số 0x110000 tương ứng với 17 mặt phẳng của mỗi điểm mã 0x10000.
neuralmer

2
PSA: Wikipedia không phải là một nguồn thực. Nhìn vào tài liệu tham khảo thực tế của bài báo.
Nyerguds

0

Số byte tối đa để hỗ trợ US-ASCII, một mã hóa bảng chữ cái tiếng Anh tiêu chuẩn, là 1. Nhưng việc giới hạn văn bản đối với tiếng Anh đang trở nên ít được mong muốn hoặc thực tế hơn theo thời gian.

Unicode được thiết kế để đại diện cho các nét chữ của tất cả các ngôn ngữ của con người, cũng như nhiều loại ký hiệu, với nhiều đặc điểm kết xuất khác nhau. UTF-8 là một mã hóa hiệu quả cho Unicode, mặc dù vẫn thiên về tiếng Anh. UTF-8 tự đồng bộ hóa: ranh giới ký tự được xác định dễ dàng bằng cách quét các mẫu bit được xác định rõ theo một trong hai hướng.

Mặc dù số byte tối đa cho mỗi ký tự UTF-8 là 3 để chỉ hỗ trợ không gian địa chỉ 2 byte của Mặt phẳng 0, Mặt phẳng đa ngôn ngữ cơ bản (BMP), có thể được chấp nhận là hỗ trợ tối thiểu trong một số ứng dụng, nó là 4 để hỗ trợ tất cả 17 mặt phẳng hiện tại của Unicode (tính đến năm 2019). Cần lưu ý rằng nhiều ký tự "biểu tượng cảm xúc" phổ biến có khả năng nằm trong Mặt phẳng 16, yêu cầu 4 byte.

Tuy nhiên, điều này chỉ dành cho glyphs ký tự cơ bản. Ngoài ra còn có các công cụ sửa đổi khác nhau, chẳng hạn như làm cho các dấu trọng âm xuất hiện trên ký tự trước đó và cũng có thể liên kết với nhau một số điểm mã tùy ý để tạo ra một "grapheme" phức tạp. Do đó, trong lập trình thế giới thực, việc sử dụng hoặc giả định số byte tối đa cố định cho mỗi ký tự cuối cùng sẽ dẫn đến sự cố cho ứng dụng của bạn.

Những cân nhắc này ngụ ý rằng các chuỗi ký tự UTF-8 không được "mở rộng" thành các mảng có độ dài cố định trước khi xử lý, như đôi khi đã được thực hiện. Thay vào đó, lập trình nên được thực hiện trực tiếp, sử dụng các hàm chuỗi được thiết kế đặc biệt cho UTF-8.


Lưu ý: đoạn văn về việc không sử dụng mảng ký tự có độ rộng cố định là ý kiến ​​của riêng tôi. Tôi sẵn sàng chỉnh sửa câu trả lời này để phản hồi các ý kiến.
David Spector
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.