Sự khác biệt giữa UTF-8, UTF-16 và UTF-32 là gì?
Tôi hiểu rằng tất cả chúng sẽ lưu trữ Unicode và mỗi loại sử dụng một số byte khác nhau để thể hiện một ký tự. Có một lợi thế để chọn cái này hơn cái kia không?
Sự khác biệt giữa UTF-8, UTF-16 và UTF-32 là gì?
Tôi hiểu rằng tất cả chúng sẽ lưu trữ Unicode và mỗi loại sử dụng một số byte khác nhau để thể hiện một ký tự. Có một lợi thế để chọn cái này hơn cái kia không?
Câu trả lời:
UTF-8 có lợi thế trong trường hợp các ký tự ASCII đại diện cho phần lớn các ký tự trong một khối văn bản, vì UTF-8 mã hóa chúng thành 8 bit (như ASCII). Một điều thuận lợi nữa là tệp UTF-8 chỉ chứa các ký tự ASCII có cùng mã hóa với tệp ASCII.
UTF-16 tốt hơn khi ASCII không chiếm ưu thế, vì chủ yếu sử dụng 2 byte cho mỗi ký tự. UTF-8 sẽ bắt đầu sử dụng 3 byte trở lên cho các ký tự bậc cao hơn trong đó UTF-16 chỉ còn 2 byte cho hầu hết các ký tự.
UTF-32 sẽ bao gồm tất cả các ký tự có thể trong 4 byte. Điều này làm cho nó khá bồng bềnh. Tôi không thể nghĩ ra bất kỳ lợi thế nào khi sử dụng nó.
Nói ngắn gọn:
wchar_t
mặc định là 4 byte. gcc có một tùy chọn -fshort-wchar
làm giảm kích thước xuống 2 byte, nhưng phá vỡ tính tương thích nhị phân với lib std.
UTF-8 là biến 1 đến 4 byte.
UTF-16 là biến 2 hoặc 4 byte.
UTF-32 được cố định 4 byte.
Lưu ý: UTF-8 có thể mất 1 đến 6 byte với quy ước mới nhất: https://lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html
Unicode định nghĩa một bộ ký tự khổng lồ duy nhất, gán một giá trị số nguyên duy nhất cho mỗi ký hiệu đồ họa (đó là một sự đơn giản hóa lớn và không thực sự đúng, nhưng nó đủ gần cho mục đích của câu hỏi này). UTF-8/16/32 đơn giản là những cách khác nhau để mã hóa điều này.
Tóm lại, UTF-32 sử dụng các giá trị 32 bit cho mỗi ký tự. Điều đó cho phép họ sử dụng mã có chiều rộng cố định cho mỗi ký tự.
UTF-16 theo mặc định sử dụng 16 bit, nhưng điều đó chỉ cung cấp cho bạn 65 nghìn ký tự có thể, không đủ gần cho bộ Unicode đầy đủ. Vì vậy, một số ký tự sử dụng các cặp giá trị 16 bit.
Và UTF-8 theo mặc định sử dụng các giá trị 8 bit, điều đó có nghĩa là 127 giá trị đầu tiên là các ký tự byte đơn có độ rộng cố định (bit quan trọng nhất được sử dụng để biểu thị rằng đây là khởi đầu của chuỗi nhiều byte, để lại 7 bit cho giá trị ký tự thực tế). Tất cả các ký tự khác được mã hóa thành chuỗi có tối đa 4 byte (nếu bộ nhớ phục vụ).
Và điều đó dẫn chúng ta đến những lợi thế. Bất kỳ ký tự ASCII nào cũng tương thích trực tiếp với UTF-8, vì vậy để nâng cấp các ứng dụng cũ, UTF-8 là một lựa chọn phổ biến và rõ ràng. Trong hầu hết các trường hợp, nó cũng sẽ sử dụng ít bộ nhớ nhất. Mặt khác, bạn không thể đảm bảo về độ rộng của ký tự. Nó có thể rộng 1, 2, 3 hoặc 4 ký tự, điều này làm cho việc thao tác chuỗi trở nên khó khăn.
UTF-32 thì ngược lại, nó sử dụng nhiều bộ nhớ nhất (mỗi ký tự rộng 4 byte cố định), nhưng mặt khác, bạn biết rằng mọi ký tự đều có độ dài chính xác này, do đó thao tác chuỗi trở nên đơn giản hơn rất nhiều. Bạn có thể tính số lượng ký tự trong một chuỗi đơn giản từ độ dài tính bằng byte của chuỗi. Bạn không thể làm điều đó với UTF-8.
UTF-16 là một sự thỏa hiệp. Nó cho phép hầu hết các ký tự khớp với giá trị 16 bit có chiều rộng cố định. Vì vậy, miễn là bạn không có biểu tượng Trung Quốc, nốt nhạc hoặc một số người khác, bạn có thể giả sử rằng mỗi ký tự có chiều rộng 16 bit. Nó sử dụng ít bộ nhớ hơn UTF-32. Nhưng đó là trong một số cách "tồi tệ nhất của cả hai thế giới". Nó hầu như luôn sử dụng nhiều bộ nhớ hơn UTF-8, và nó vẫn không tránh được vấn đề làm hỏng UTF-8 (các ký tự có độ dài thay đổi).
Cuối cùng, thật hữu ích khi chỉ đi với những gì nền tảng hỗ trợ. Windows sử dụng UTF-16 trong nội bộ, vì vậy trên Windows, đó là sự lựa chọn rõ ràng.
Linux thay đổi một chút, nhưng họ thường sử dụng UTF-8 cho mọi thứ tuân thủ Unicode.
Vì vậy, câu trả lời ngắn gọn: Tất cả ba mã hóa có thể mã hóa cùng một bộ ký tự, nhưng chúng đại diện cho mỗi ký tự là các chuỗi byte khác nhau.
Unicode là một tiêu chuẩn và về UTF-x mà bạn có thể nghĩ là một triển khai kỹ thuật cho một số mục đích thực tế:
Tôi đã cố gắng đưa ra một lời giải thích đơn giản trong blogpost của tôi .
yêu cầu 32 bit (4 byte) để mã hóa bất kỳ ký tự nào . Ví dụ: để thể hiện điểm mã ký tự "A" bằng cách sử dụng lược đồ này, bạn sẽ cần phải viết 65 bằng số nhị phân 32 bit:
00000000 00000000 00000000 01000001 (Big Endian)
Nếu bạn xem xét kỹ hơn, bạn sẽ lưu ý rằng bảy bit đúng nhất thực sự là các bit giống nhau khi sử dụng sơ đồ ASCII. Nhưng vì UTF-32 là lược đồ độ rộng cố định , chúng tôi phải đính kèm ba byte bổ sung. Có nghĩa là nếu chúng ta có hai tệp chỉ chứa ký tự "A", một tệp được mã hóa ASCII và tệp còn lại được mã hóa UTF-32, kích thước của chúng sẽ tương ứng là 1 byte và 4 byte.
Nhiều người nghĩ rằng vì UTF-32 sử dụng chiều rộng cố định 32 bit để thể hiện điểm mã, UTF-16 là chiều rộng cố định 16 bit. SAI LẦM!
Trong UTF-16, điểm mã có thể được biểu thị bằng 16 bit, HOẶC 32 bit. Vì vậy, sơ đồ này là hệ thống mã hóa chiều dài thay đổi. Lợi thế so với UTF-32 là gì? Ít nhất là đối với ASCII, kích thước tệp sẽ không gấp 4 lần bản gốc (nhưng vẫn gấp đôi), vì vậy chúng tôi vẫn không tương thích ngược với ASCII.
Vì 7 bit là đủ để biểu thị ký tự "A", giờ đây chúng ta có thể sử dụng 2 byte thay vì 4 như UTF-32. Nó sẽ trông giống như:
00000000 01000001
Bạn đã đoán đúng .. Trong UTF-8, điểm mã có thể được biểu diễn bằng cách sử dụng 32, 16, 24 hoặc 8 bit, và như hệ thống UTF-16, điểm này cũng là hệ thống mã hóa có độ dài thay đổi.
Cuối cùng, chúng ta có thể biểu diễn "A" giống như cách chúng ta biểu diễn nó bằng hệ thống mã hóa ASCII:
01001101
Hãy xem xét chữ cái "" của Trung Quốc - mã hóa UTF-8 của nó là:
11101000 10101010 10011110
Trong khi mã hóa UTF-16 của nó ngắn hơn:
10001010 10011110
Để hiểu cách trình bày và cách giải thích, hãy truy cập bài viết gốc.
UTF-8 sẽ là không gian hiệu quả nhất trừ khi phần lớn các nhân vật đến từ không gian nhân vật CJK (Trung Quốc, Nhật Bản và Hàn Quốc).
UTF-32 là tốt nhất để truy cập ngẫu nhiên bằng cách bù ký tự vào một mảng byte.
0xxxxxxx
nhị phân. Tất cả các ký tự hai byte bắt đầu 110xxxxx
bằng một byte thứ hai 10xxxxxx
. Vì vậy, giả sử ký tự đầu tiên của ký tự hai byte bị mất. Ngay khi bạn nhìn thấy 10xxxxxx
mà không có trước 110xxxxxx
, bạn có thể xác định chắc chắn rằng một byte bị mất hoặc bị hỏng và loại bỏ ký tự đó (hoặc yêu cầu lại từ máy chủ hoặc bất cứ điều gì), và tiếp tục cho đến khi bạn gặp lại byte đầu tiên hợp lệ .
Tôi đã thực hiện một số thử nghiệm để so sánh hiệu suất cơ sở dữ liệu giữa UTF-8 và UTF-16 trong MySQL.
Trong UTF-32, tất cả các ký tự được mã hóa bằng 32 bit. Ưu điểm là bạn có thể dễ dàng tính toán độ dài của chuỗi. Nhược điểm là đối với mỗi ký tự ASCII, bạn lãng phí thêm ba byte.
Trong các ký tự UTF-8 có độ dài thay đổi, các ký tự ASCII được mã hóa bằng một byte (tám bit), hầu hết các ký tự đặc biệt phương tây được mã hóa bằng hai byte hoặc ba byte (ví dụ € là ba byte) và các ký tự kỳ lạ hơn có thể chiếm đến bốn byte. Rõ ràng nhược điểm là, một ưu tiên bạn không thể tính được độ dài của chuỗi. Nhưng nó cần ít byte hơn để mã văn bản bảng chữ cái Latinh (tiếng Anh), so với UTF-32.
UTF-16 cũng có chiều dài thay đổi. Các ký tự được mã hóa bằng hai byte hoặc bốn byte. Tôi thực sự không nhìn thấy điểm. Nó có nhược điểm là chiều dài thay đổi, nhưng không có lợi thế là tiết kiệm không gian nhiều như UTF-8.
Trong số ba, rõ ràng UTF-8 là phổ biến rộng rãi nhất.
Tùy thuộc vào môi trường phát triển của bạn, bạn thậm chí có thể không có lựa chọn mã hóa kiểu dữ liệu chuỗi nào của mình sẽ sử dụng nội bộ.
Nhưng để lưu trữ và trao đổi dữ liệu, tôi sẽ luôn sử dụng UTF-8, nếu bạn có sự lựa chọn. Nếu bạn có hầu hết dữ liệu ASCII, điều này sẽ cung cấp cho bạn lượng dữ liệu nhỏ nhất để truyền, trong khi vẫn có thể mã hóa mọi thứ. Tối ưu hóa cho I / O tối thiểu là cách để đi trên các máy hiện đại.
Như đã đề cập, sự khác biệt chủ yếu là kích thước của các biến cơ bản, trong mỗi trường hợp sẽ lớn hơn để cho phép nhiều ký tự được biểu diễn.
Tuy nhiên, phông chữ, mã hóa và mọi thứ rất phức tạp (không cần thiết?), Vì vậy cần một liên kết lớn để điền chi tiết hơn:
http://www.cs.tut.fi/~jkorpela/chars.html#ascii
Đừng mong đợi để hiểu tất cả, nhưng nếu sau này bạn không muốn gặp vấn đề thì nên học càng nhiều càng tốt, càng sớm càng tốt (hoặc chỉ cần nhờ người khác sắp xếp nó cho bạn).
Paul.
Nói tóm lại, lý do duy nhất để sử dụng UTF-16 hoặc UTF-32 là để hỗ trợ các tập lệnh không phải tiếng Anh và cổ.
Tôi đã tự hỏi tại sao mọi người chọn mã hóa không phải UTF-8 khi nó rõ ràng hiệu quả hơn cho các mục đích lập trình / web.
Một quan niệm sai lầm phổ biến - số hậu tố KHÔNG phải là một dấu hiệu cho thấy khả năng của nó. Tất cả chúng đều hỗ trợ Unicode hoàn chỉnh, chỉ cần UTF-8 có thể xử lý ASCII bằng một byte duy nhất, do đó, HIỆU QUẢ / ít bị hỏng hơn đối với CPU và qua internet.
Một số cách đọc tốt: http://www.personal.psu.edu/ejp10/bloss/gotunicode/2007/10/which_utf_do_i_use.html và http://utf8everywhere.org