Có bao nhiêu byte để một ký tự Unicode mất?


239

Tôi hơi bối rối về mã hóa. Theo như tôi biết thì các ký tự ASCII cũ đã lấy một byte cho mỗi ký tự. Một ký tự Unicode cần bao nhiêu byte?

Tôi giả sử rằng một ký tự Unicode có thể chứa mọi ký tự có thể từ bất kỳ ngôn ngữ nào - tôi có đúng không? Vì vậy, cần bao nhiêu byte cho mỗi ký tự?

Và UTF-7, UTF-6, UTF-16 v.v ... nghĩa là gì? Chúng có phải là phiên bản khác nhau của Unicode không?

Tôi đã đọc bài viết trên Wikipedia về Unicode nhưng nó khá khó đối với tôi. Tôi mong muốn được nhìn thấy một câu trả lời đơn giản.



15
Xin lỗi, không có câu trả lời đơn giản. Tôi tìm thấy toàn bộ một chút lộn xộn. Unicode được lập hóa đơn là sử dụng hai byte và có thể đại diện cho tất cả các ký tự, nhưng hóa ra hai byte không đủ.
Jonathan Wood

12
"Câu trả lời đơn giản": Một ký tự unicode mất 1-4 byte. Unicode bao gồm rất nhiều ngôn ngữ nhưng không phải tất cả. Lần trước tôi đã xem, ví dụ Klingon không phải là một bộ ký tự Unicode chính thức.
Peter G.

9
Klingon không phải là một phần của tiêu chuẩn Unicode, không. Thay vào đó, nó sử dụng Khu vực sử dụng riêng của Uniode (U + F8D0 - U + F8FF).
Rémy Lebeau

1
Câu hỏi cứu tinh - cảm ơn. Tình huống của tôi là lưu trữ dữ liệu qua các LMS tương thích SCORM 1.2 ... tiêu chuẩn cho SCORM 1.2 'cmi.suspend_data' là 4096 byte dữ liệu mà nhà phát triển trước đó cho rằng chúng tôi có thể lưu trữ 4096 ký tự. Ôi trời, anh ta đã sai - Tôi vừa mới phát hiện ra lý do tại sao việc đánh dấu trang của chúng tôi thất bại trong các khóa học dài. Vì vậy, bây giờ tôi biết vì chúng tôi đang sử dụng UTF-8, phải mất 4 byte cho mỗi ký tự cho chúng tôi 1024 ký tự.
danjah

Câu trả lời:


147

Bạn sẽ không thấy một câu trả lời đơn giản vì không có câu trả lời.

Đầu tiên, Unicode không chứa "mọi ký tự từ mọi ngôn ngữ", mặc dù nó chắc chắn sẽ thử.

Bản thân Unicode là một ánh xạ, nó định nghĩa các điểm mã và một điểm mã là một số, thường được liên kết với một ký tự. Tôi nói thường bởi vì có những khái niệm như kết hợp các nhân vật. Bạn có thể quen thuộc với những thứ như dấu, hoặc ô. Chúng có thể được sử dụng với một ký tự khác, chẳng hạn như một ahoặc một uđể tạo ra một ký tự logic mới. Do đó, một ký tự có thể bao gồm 1 hoặc nhiều điểm mã.

Để có ích trong các hệ thống máy tính, chúng ta cần chọn một đại diện cho thông tin này. Đó là các mã hóa unicode khác nhau, chẳng hạn như utf-8, utf-16le, utf-32, v.v. Chúng được phân biệt chủ yếu bởi kích thước của mã của chúng. UTF-32 là mã hóa đơn giản nhất, nó có codeunit là 32 bit, có nghĩa là một mật mã riêng lẻ phù hợp thoải mái với một codeunit. Các mã hóa khác sẽ có các tình huống trong đó một mật mã sẽ cần nhiều mã hóa hoặc mã hóa cụ thể đó hoàn toàn không thể được trình bày trong mã hóa (đây là một vấn đề với UCS-2).

Do tính linh hoạt của việc kết hợp các ký tự, ngay cả trong một mã hóa nhất định, số byte trên mỗi ký tự có thể thay đổi tùy thuộc vào ký tự và dạng chuẩn hóa. Đây là một giao thức để xử lý các ký tự có nhiều hơn một đại diện (bạn có thể nói "an 'a' with an accent"đó là 2 điểm mã, một trong số đó là char kết hợp hoặc "accented 'a'"là một điểm mã).


1
ĐỒNG Ý. Sau đó, có bao nhiêu byte lấy một ký tự cho trước được biểu thị trong một mật mã đã cho? Ví dụ, không gian không phá vỡ.
Nicolas Barbulesco

Các ký tự kết hợp làm cho cuộc sống của một lập trình viên trở thành một địa ngục khi viết các hàm strlen (), chất nền () và các hàm thao tác chuỗi khác trên mảng UTF8. Loại công việc này sẽ không bao giờ hoàn thành và luôn có lỗi.
Nulik

Tôi đã viết một bản demo cho thấy các tệp được mã hóa Windows-1252, UTF8 và UTF8-BOM được giải thích với mỗi mã hóa và so sánh sự bình đẳng giữa các kết quả: github.com/vladyrn/encodings_demo
Vlad

195

Thật kỳ lạ, không ai chỉ ra cách tính có bao nhiêu byte đang lấy một ký tự Unicode. Dưới đây là quy tắc cho các chuỗi được mã hóa UTF-8:

Binary    Hex          Comments
0xxxxxxx  0x00..0x7F   Only byte of a 1-byte character encoding
10xxxxxx  0x80..0xBF   Continuation byte: one of 1-3 bytes following the first
110xxxxx  0xC0..0xDF   First byte of a 2-byte character encoding
1110xxxx  0xE0..0xEF   First byte of a 3-byte character encoding
11110xxx  0xF0..0xF7   First byte of a 4-byte character encoding

Vì vậy, câu trả lời nhanh là: phải mất 1 đến 4 byte, tùy thuộc vào cái đầu tiên sẽ cho biết số lượng byte sẽ chiếm.


8
Tôi tin rằng giá trị Hex tối đa cho ký tự 4 byte là 0xF7 (không phải 0xF4).
DJPJ

Cảm ơn bạn rất nhiều! Tôi chỉ kiểm soát + thông qua tiêu chuẩn IETF và tôi không tìm thấy gì về mã hóa, và bài báo tôi đang đọc không đi sâu vào chi tiết để cho biết có bao nhiêu bit được sử dụng để biểu thị số lượng mã theo dõi điểm trên mỗi "ký tự".
MarcusJ

1
Bây giờ là trên trang thứ hai của tờ giới thiệu "giới thiệu cho các thành viên nhóm mới" của tôi, cùng với hai bình luận đầu tiên vui nhộn
Cee McSharpface

1
0xF4 không phải là một lỗi mà là một sự làm rõ. Các điểm mã Unicode nằm trong phạm vi 0-0x10ffff, vì vậy, điểm mã cuối cùng được mã hóa là F4 8F BF BF.
Frediano Ziglio

38

Tôi biết câu hỏi này đã cũ và đã có câu trả lời được chấp nhận, nhưng tôi muốn đưa ra một vài ví dụ (hy vọng nó sẽ hữu ích cho ai đó).

Theo như tôi biết thì các ký tự ASCII cũ đã lấy một byte cho mỗi ký tự.

Đúng. Trên thực tế, vì ASCII là mã hóa 7 bit, nó hỗ trợ 128 mã (95 mã này có thể in được), do đó, nó chỉ sử dụng nửa byte (nếu điều đó có ý nghĩa gì).

Một ký tự Unicode cần bao nhiêu byte?

Unicode chỉ ánh xạ các ký tự đến các điểm mã. Nó không định nghĩa cách mã hóa chúng. Tệp văn bản không chứa các ký tự Unicode, nhưng byte / octet có thể đại diện cho các ký tự Unicode.

Tôi giả sử rằng một ký tự Unicode có thể chứa mọi ký tự có thể từ bất kỳ ngôn ngữ nào - tôi có đúng không?

Không. Nhưng gần như vậy. Vì vậy, về cơ bản là có. Nhưng vẫn không có.

Vì vậy, cần bao nhiêu byte cho mỗi ký tự?

Giống như câu hỏi thứ 2 của bạn.

Và UTF-7, UTF-6, UTF-16 v.v ... nghĩa là gì? Chúng có phải là một số phiên bản Unicode không?

Không, đó là những bảng mã. Chúng xác định cách byte / octet thể hiện các ký tự Unicode.

Một vài ví dụ. Nếu một số trong số đó không thể được hiển thị trong trình duyệt của bạn (có thể do phông chữ không hỗ trợ chúng), hãy đi tới http://codepoints.net/U+1F6AA(thay thế 1F6AAbằng mật mã ở dạng hex) để xem hình ảnh.

    • U + 0061 LATIN NHỎ BÀI A: a
      • Số 97
      • UTF-8: 61
      • UTF-16: 00 61
    • ĐĂNG KÝ BẢN QUYỀN U + 00A9: ©
      • Số: 169
      • UTF-8: C2 A9
      • UTF-16: 00 A9
    • ĐĂNG KÝ ĐĂNG KÝ U + 00AE: ®
      • Số: 174
      • UTF-8: C2 AE
      • UTF-16: 00 AE
    • U + 1337 PHONG CÁCH DÂN TỘC ETHIOPIC:
      • Số: 4919
      • UTF-8: E1 8C B7
      • UTF-16: 13 37
    • U + 2014 EM DASH:
      • Số: 8212
      • UTF-8: E2 80 94
      • UTF-16: 20 14
    • U + 2030 M MII ĐĂNG KÝ:
      • Số: 8240
      • UTF-8: E2 80 B0
      • UTF-16: 20 30
    • ĐĂNG KÝ U + 20AC EURO:
      • Số: 8364
      • UTF-8: E2 82 AC
      • UTF-16: 20 AC
    • ĐĂNG KÝ NHÃN HIỆU U + 2122:
      • Số 8482
      • UTF-8: E2 84 A2
      • UTF-16: 21 22
    • U + 2603 SNOWMAN:
      • Số: 9731
      • UTF-8: E2 98 83
      • UTF-16: 26 03
    • ĐIỆN THOẠI ĐEN U + 260E:
      • Số: 9742
      • UTF-8: E2 98 8E
      • UTF-16: 26 0E
    • U + 2614 UMBRELLA VỚI RAIN DROPS:
      • Số: 9748
      • UTF-8: E2 98 94
      • UTF-16: 26 14
    • U + 263A MẶT NẠ TRẮNG TRẮNG:
      • Số: 9786
      • UTF-8: E2 98 BA
      • UTF-16: 26 3A
    • CỜ ĐEN U91:
      • Số 9873
      • UTF-8: E2 9A 91
      • UTF-16: 26 91
    • BIỂU TƯỢNG U + 269B ATOM:
      • Số 9883
      • UTF-8: E2 9A 9B
      • UTF-16: 26 9B
    • U + 2708 HÀNG KHÔNG:
      • Số: 9992
      • UTF-8: E2 9C 88
      • UTF-16: 27 08
    • U + 271E CHIA SẺ TRẮNG LATIN TRẮNG:
      • Số: 10014
      • UTF-8: E2 9C 9E
      • UTF-16: 27 1E
    • U + 3020 MẶT B POSTNG SAU:
      • Số: 12320
      • UTF-8: E3 80 A0
      • UTF-16: 30 20
    • U + 8089 Ý TƯỞNG CHỨNG MINH CỦA CJK-8089:
      • Số: 32905
      • UTF-8: E8 82 89
      • UTF-16: 80 89
    • P + UF 1A4A9 CỦA POO: 💩
      • Số: 128169
      • UTF-8: F0 9F 92 A9
      • UTF-16: D8 3D DC A9
    • ROCKET U + 1F680: 🚀
      • Số: 128640
      • UTF-8: F0 9F 9A 80
      • UTF-16: D8 3D DE 80

Được rồi tôi sẽ được mang đi ...

Những điều lý thú:


Các đơn vị mã trong UTF-16 rộng 16 bit. Bạn chỉ cho họ một khoảng trống ở giữa, đó là sai lệch. Thay vào đó, đại diện UTF-16 cho © nên thay 00A900 A9(sẽ là UTF-16BE).
Roland Illig

Có gì khác biệt? Không phải là đứng cho endian lớn? Ông đã viết nó bằng endian lớn, và vì vậy một tập tin được viết bằng UTF-16 endian lớn sẽ giống như UTF-16BE, phải không?
HappyPandaFace

6
Sửa chữa: 1) ASCII là 7 bit, một byte là 8 bit, vì vậy nó nhiều hơn một nửa. 2) Unicode xác định cách mã hóa các điểm mã. UTF-8, UTF-16 và UTF-32 được xác định trong Tiêu chuẩn Unicode.
Jonathan Rosenne

3
@JonathanRosenne Tôi nghĩ rằng anh ấy có nghĩa là nó chỉ sử dụng một nửa giá trị có thể biểu thị bằng 8 bit, chứ không phải nó sử dụng một nửa số bit.
Aritz Lopez

2
Tôi thực sự thích các ví dụ. Họ nêu bật lý do tại sao người ta có thể thích UTF-16 hơn UTF-8 chẳng hạn. Các nhà phát triển phần mềm khác nhau có thể chọn các bảng mã khác nhau dựa trên các ký tự Unicode có khả năng được sử dụng nhiều hơn. Ở Trung Quốc / Nhật Bản chẳng hạn, UTF-16 (2-byte) có ý nghĩa hơn UTF-8 cho họ, bởi vì các nhân vật cùng thường sẽ cần hai lần như nhiều byte để mã hóa theo UTF-8
mike

29

Nói Unicodemột cách đơn giản là một tiêu chuẩn được gán một số (được gọi là điểm mã) cho tất cả các ký tự trên thế giới (Nó vẫn đang hoạt động).

Bây giờ bạn cần biểu diễn các điểm mã này bằng byte, được gọi là character encoding. UTF-8, UTF-16, UTF-6là những cách thể hiện những nhân vật đó.

UTF-8là mã hóa ký tự đa bào. Các ký tự có thể có 1 đến 6 byte (một số trong số chúng có thể không được yêu cầu ngay bây giờ).

UTF-32 mỗi ký tự có 4 byte một ký tự.

UTF-16sử dụng 16 bit cho mỗi ký tự và nó chỉ đại diện cho một phần của các ký tự Unicode được gọi là BMP (cho tất cả các mục đích thực tế là đủ). Java sử dụng mã hóa này trong chuỗi của nó.


10
Unicode là một bộ mã 21 bit và 4 byte là đủ để thể hiện bất kỳ ký tự Unicode nào trong UTF-8. UTF-16 sử dụng các chất thay thế để thể hiện các ký tự bên ngoài BMP (mặt phẳng đa ngôn ngữ cơ bản); nó cần 2 hoặc 4 byte để thể hiện bất kỳ ký tự Unicode hợp lệ nào. UCS-2 là biến thể 16 bit duy nhất của UTF-16 mà không hỗ trợ cho người thay thế hoặc nhân vật bên ngoài BMP.
Jonathan Leffler

1
Bạn nói đúng. Bản gốc UTF-8 có 6 byte để chứa 32 bit. Tôi thực sự không muốn làm phức tạp mọi thứ vì anh ấy đã bị nhầm lẫn với tài liệu wiki :)
Zimbabao

3
Câu trả lời này nói rằng UTF-16 không thể mã hóa các điểm mã BMP. Điều này là không chính xác, vì chúng có thể được mã hóa giống như trong UTF-8 bằng cách sử dụng các cặp thay thế. (Bạn phải nghĩ về UCS-2 đã lỗi thời, trước khi Unicode 2.0 xuất hiện, chỉ mã hóa các điểm mã 16 bit.) Ngoài ra, Java không sử dụng UTF-16, nó sử dụng một dạng đã sửa đổi trong đó điểm mã 0 được mã hóa khác nhau.
rdb

@rdb - Nó ngược lại. Câu trả lời nói rằng UTF-16 đại diện cho BMP.
Nicolas Barbulesco

3
Tôi lầm tưởng; Tôi đã có ý nói "không phải BMP". Lỗi trong câu trả lời là nó nói rằng UTF-16 đại diện cho các ký tự BMP, không chính xác. UTF-16 có thể mã hóa tất cả các ký tự unicode-- các ký tự không phải BMP được mã hóa thông qua các cặp thay thế. Có lẽ người trả lời đã nhầm lẫn với UCS-2.
rdb

17

Trong UTF-8:

1 byte:       0 -     7F     (ASCII)
2 bytes:     80 -    7FF     (all European plus some Middle Eastern)
3 bytes:    800 -   FFFF     (multilingual plane incl. the top 1792 and private-use)
4 bytes:  10000 - 10FFFF

Trong UTF-16:

2 bytes:      0 -   D7FF     (multilingual plane except the top 1792 and private-use )
4 bytes:   D800 - 10FFFF

Trong UTF-32:

4 bytes:      0 - 10FFFF

10FFFF là định nghĩa mã hóa cuối cùng theo định nghĩa và được định nghĩa theo cách đó bởi vì đó là giới hạn kỹ thuật của UTF-16.

Đây cũng là loại tiền mã hóa lớn nhất UTF-8 có thể mã hóa thành 4 byte, nhưng ý tưởng đằng sau mã hóa của UTF-8 cũng hoạt động đối với mã hóa 5 và 6 byte để bao trùm các mã hóa cho đến 7FFFFFFF, tức là. một nửa những gì UTF-32 có thể.


8

Trong Unicode, câu trả lời không dễ dàng được đưa ra. Vấn đề, như bạn đã chỉ ra, là các bảng mã.

Với bất kỳ câu tiếng Anh nào không có ký tự dấu phụ, câu trả lời cho UTF-8 sẽ có nhiều byte bằng ký tự và đối với UTF-16, nó sẽ là số ký tự nhân hai lần.

Mã hóa duy nhất trong đó (tính đến thời điểm hiện tại) chúng ta có thể đưa ra tuyên bố về kích thước là UTF-32. Luôn có 32 bit cho mỗi ký tự, mặc dù tôi tưởng tượng rằng các điểm mã được chuẩn bị cho UTF-64 trong tương lai :)

Điều gây khó khăn là ít nhất hai điều:

  1. gồm các ký tự, trong đó thay vì sử dụng thực thể ký tự đã có dấu / diacritic (À), một người dùng đã quyết định kết hợp dấu và ký tự cơ sở (`A).
  2. điểm mã. Điểm mã là phương thức mà mã hóa UTF cho phép mã hóa nhiều hơn số bit cung cấp cho chúng tên của chúng thường cho phép. Ví dụ, UTF-8 chỉ định một số byte nhất định mà không hợp lệ, nhưng khi được theo sau bởi một byte tiếp tục hợp lệ sẽ cho phép mô tả một ký tự nằm ngoài phạm vi 8 bit là 0..255. Xem các ví dụ và mã hóa quá dài bên dưới trong bài viết Wikipedia về UTF-8.
    • Các ví dụ tuyệt vời cho có là € nhân vật (mã điểm U+20ACcó thể được biểu diễn dưới dạng ba-byte chuỗi E2 82 AChoặc bốn byte chuỗi F0 82 82 AC.
    • Cả hai đều hợp lệ và điều này cho thấy câu trả lời phức tạp như thế nào khi nói về "Unicode" chứ không phải về một mã hóa cụ thể của Unicode, chẳng hạn như UTF-8 hoặc UTF-16.


4

Tôi cũng vừa mới mở trang Wikipedia trên đó và trong phần giới thiệu tôi thấy "Unicode có thể được thực hiện bằng các mã hóa ký tự khác nhau. Các mã hóa được sử dụng phổ biến nhất là UTF-8 (sử dụng một byte cho bất kỳ ký tự ASCII nào, có các giá trị mã giống nhau trong cả mã hóa UTF-8 và ASCII và tối đa bốn byte cho các ký tự khác), UCS-2 đã lỗi thời (sử dụng hai byte cho mỗi ký tự nhưng không thể mã hóa mọi ký tự trong tiêu chuẩn Unicode hiện tại) "

Như trích dẫn này chứng minh, vấn đề của bạn là bạn cho rằng Unicode là một cách mã hóa ký tự duy nhất. Thực tế, có nhiều dạng Unicode và một lần nữa trong trích dẫn đó, một trong số chúng thậm chí có 1 byte cho mỗi ký tự giống như những gì bạn đã quen.

Vì vậy, câu trả lời đơn giản của bạn mà bạn muốn là nó thay đổi.


3

Đối với UTF-16, ký tự cần bốn byte (hai đơn vị mã) nếu bắt đầu bằng 0xD800 trở lên; một nhân vật như vậy được gọi là "cặp thay thế." Cụ thể hơn, một cặp thay thế có dạng:

[0xD800 - 0xDBFF]  [0xDC00 - 0xDFF]

trong đó [...] chỉ ra đơn vị mã hai byte với phạm vi đã cho. Bất cứ điều gì <= 0xD7FF là một đơn vị mã (hai byte). Bất cứ điều gì> = 0xE000 đều không hợp lệ (ngoại trừ các dấu BOM, được cho là).

Xem http://unicodebook.readthedocs.io/unicode_encodings.html , phần 7.5.



1

Từ Wiki:

UTF-8, mã hóa độ rộng biến 8 bit, tối đa hóa khả năng tương thích với ASCII;

UTF-16, mã hóa 16 bit, độ rộng thay đổi;

UTF-32, mã hóa 32 bit, độ rộng cố định.

Đây là ba mã hóa khác nhau phổ biến nhất.

  • Trong UTF-8, mỗi ký tự được mã hóa thành 1 đến 4 byte (mã hóa chiếm ưu thế)
  • Trong UTF16, mỗi ký tự được mã hóa thành 1 đến hai từ 16 bit và
  • trong UTF-32, mỗi ký tự được mã hóa thành một từ 32 bit.

1

Unicodelà một tiêu chuẩn cung cấp một số duy nhất cho mỗi ký tự. Những số duy nhất này được gọi là code points (chỉ là mã duy nhất) cho tất cả các ký tự hiện có trên thế giới (một số vẫn còn được thêm vào).

Đối với các mục đích khác nhau, bạn có thể cần biểu diễn điều này code pointsbằng byte (hầu hết các ngôn ngữ lập trình đều làm như vậy) và đây là nơi Character Encodingkhởi động.

UTF-8, UTF-16, UTF-32Và như vậy là tất cả Character Encodings, và điểm mã Unicode của được trình bày trong những mã hóa, theo những cách khác nhau.


UTF-8 mã hóa có độ dài thay đổi chiều rộng và các ký tự, được mã hóa trong đó, có thể chiếm từ 1 đến 4 byte;

UTF-16có độ dài và ký tự thay đổi, được mã hóa trong đó, có thể mất 1 hoặc 2 byte (là 8 hoặc 16 bit). Điều này chỉ đại diện cho một phần của tất cả các ký tự Unicode được gọi là BMP (Mặt phẳng đa ngôn ngữ cơ bản) và nó đủ cho hầu hết các trường hợp. Java sử dụng UTF-16mã hóa cho các chuỗi và ký tự của nó;

UTF-32 có độ dài cố định và mỗi ký tự mất chính xác 4 byte (32 bit).

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.