Sự khác biệt giữa UTF-8 và UTF-16?


137

Sự khác biệt giữa UTF-8 và UTF-16? Tại sao chúng ta cần những thứ này?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();

2
jon skeet có một bài viết hay về mã hóa .... csharpindepth.com/Articles/General/Unicode.aspx
Mitch Wheat

Câu trả lời:


284

Tôi tin rằng có rất nhiều bài viết hay về điều này trên Web, nhưng đây là một bản tóm tắt ngắn.

Cả UTF-8 và UTF-16 đều được mã hóa theo chiều dài thay đổi. Tuy nhiên, trong UTF-8, một ký tự có thể chiếm tối thiểu 8 bit, trong khi ở độ dài ký tự UTF-16 bắt đầu bằng 16 bit.

Ưu điểm chính của UTF-8:

  • Các ký tự ASCII cơ bản như chữ số, ký tự Latinh không có dấu, v.v ... chiếm một byte giống hệt với biểu diễn US-ASCII. Bằng cách này, tất cả các chuỗi US-ASCII trở thành UTF-8 hợp lệ, cung cấp khả năng tương thích ngược khá tốt trong nhiều trường hợp.
  • Không có byte null, cho phép sử dụng các chuỗi kết thúc null, điều này cũng giới thiệu rất nhiều khả năng tương thích ngược.
  • UTF-8 độc lập với thứ tự byte, vì vậy bạn không phải lo lắng về vấn đề Big Endian / Little Endian.

Nhược điểm chính của UTF-8:

  • Nhiều ký tự phổ biến có độ dài khác nhau, làm chậm việc lập chỉ mục bằng cách mã hóa và tính toán số lượng điểm mã một cách khủng khiếp.
  • Mặc dù thứ tự byte không thành vấn đề, đôi khi UTF-8 vẫn có BOM (dấu thứ tự byte) để thông báo rằng văn bản được mã hóa trong UTF-8 và cũng phá vỡ tính tương thích với phần mềm ASCII ngay cả khi văn bản chỉ chứa các ký tự ASCII . Phần mềm Microsoft (như Notepad) đặc biệt thích thêm BOM vào UTF-8.

Ưu điểm chính của UTF-16:

  • Các ký tự BMP (mặt phẳng đa ngôn ngữ cơ bản), bao gồm tiếng Latin, Cyrillic, hầu hết tiếng Trung Quốc (PRC đã hỗ trợ cho một số điểm mã ngoài BMP bắt buộc), hầu hết tiếng Nhật có thể được biểu thị bằng 2 byte. Điều này tăng tốc độ lập chỉ mục và tính toán số lượng điểm trong trường hợp văn bản không chứa các ký tự bổ sung.
  • Ngay cả khi văn bản có các ký tự bổ sung, chúng vẫn được biểu thị bằng các cặp giá trị 16 bit, có nghĩa là tổng chiều dài vẫn chia hết cho hai và cho phép sử dụng 16 bit charlàm thành phần nguyên thủy của chuỗi.

Nhược điểm chính của UTF-16:

  • Rất nhiều byte null trong các chuỗi US-ASCII, có nghĩa là không có chuỗi kết thúc null và rất nhiều bộ nhớ bị lãng phí.
  • Sử dụng nó như một mã hóa có độ dài cố định, hầu hết hoạt động, trong nhiều tình huống phổ biến (đặc biệt là ở Hoa Kỳ / EU / quốc gia có bảng chữ cái Cyrillic / Israel / Ả Rập / Iran và nhiều quốc gia khác), thường dẫn đến hỗ trợ bị hỏng trong trường hợp không có. Điều này có nghĩa là các lập trình viên phải nhận thức được các cặp thay thế và xử lý chúng đúng cách trong trường hợp có vấn đề!
  • Đó là chiều dài thay đổi, do đó, việc đếm hoặc lập chỉ mục mã hóa là tốn kém, mặc dù ít hơn UTF-8.

Nói chung, UTF-16 thường tốt hơn cho biểu diễn trong bộ nhớ vì BE / LE không liên quan ở đó (chỉ sử dụng thứ tự gốc) và lập chỉ mục nhanh hơn (chỉ cần quên xử lý các cặp thay thế đúng cách). Mặt khác, UTF-8 cực kỳ tốt cho các tệp văn bản và giao thức mạng vì không có vấn đề BE / LE và việc chấm dứt null thường có ích, cũng như khả năng tương thích ASCII.


3
Chỉ thiếu một phần BE / LE trên UTF16 :) UTF-8 có một nhược điểm khác, nó có thể tạo ra sản lượng dài hơn UTF16
bestsss

4
Vâng, tôi quên mất BE / LE. Tuy nhiên, đó không phải là vấn đề lớn, đặc biệt là sử dụng trong bộ nhớ. UTF-8 sẽ tạo đầu ra dài hơn chỉ khi có các ký tự ba byte, nhưng điều đó có nghĩa là chủ yếu là tiếng Trung và tiếng Nhật. Mặt khác, nếu văn bản chứa nhiều ký tự US-ASCII, nó có thể tạo ra đầu ra ngắn hơn, do đó, đó có phải là nhược điểm hay không phụ thuộc vào một tình huống cụ thể.
Sergei Tachenov

Tôi thậm chí không nghĩ đến việc đề cập đến pro pro ngay lập tức của utf-8, chiều dài ngắn hơn. Về đầu ra dài hơn của utf-8, đó là 'có thể' vì một lý do, tuy nhiên nếu mục tiêu ở xa về phía đông, mã hóa mặc định sẽ là utf-16. Đối với ví dụ md.update (text.getBytes ("UTF-8")); mã hóa không thành vấn đề vì hàm băm ổn định cả hai chiều.
bestsss

Cách nhanh nhất để chuyển đổi Chuỗi thành mảng byte là một cái gì đó tương tự, được đăng xuống dưới dạng mẫu
bestsss

Bạn nói rằng các ký tự có độ dài khác nhau trong UTF-8 vì vậy nó làm chậm việc lập chỉ mục và tính toán độ dài, nhưng tôi nghi ngờ về các ký tự trong UTF-16 cũng có độ dài khác nhau, nên lập chỉ mục và tính toán độ dài của UTF-16 có nhanh hơn không?
nicky_zs

19

Chúng chỉ đơn giản là các sơ đồ khác nhau để thể hiện các ký tự Unicode.

Cả hai đều có độ dài thay đổi - UTF-16 sử dụng 2 byte cho tất cả các ký tự trong mặt phẳng đa ngôn ngữ cơ bản (BMP) có chứa hầu hết các ký tự được sử dụng phổ biến.

UTF-8 sử dụng từ 1 đến 3 byte cho các ký tự trong BMP, tối đa 4 cho các ký tự trong phạm vi Unicode hiện tại của U + 0000 đến U + 1FFFFF và có thể mở rộng lên đến U + 7FFFFFFF nếu điều đó trở nên cần thiết ... nhưng đáng chú ý là tất cả các ký tự ASCII được thể hiện trong một byte đơn.

Đối với mục đích của thông báo tiêu hóa, sẽ không có vấn đề gì trong số bạn chọn, miễn là mọi người cố gắng tạo lại thông báo sử dụng cùng một tùy chọn.

Xem trang này để biết thêm về UTF-8 và Unicode.

(Lưu ý rằng tất cả các ký tự Java là các điểm mã UTF-16 trong BMP; để thể hiện các ký tự trên U + FFFF, bạn cần sử dụng các cặp thay thế trong Java.)


5

Bảo mật: Chỉ sử dụng UTF-8

Sự khác biệt giữa UTF-8 và UTF-16? Tại sao chúng ta cần những thứ này?

Đã có ít nhất một vài lỗ hổng bảo mật trong việc triển khai UTF-16 . Xem Wikipedia để biết chi tiết .

WHATWGW3C hiện đã tuyên bố rằng chỉ UTF-8 được sử dụng trên Web.

Các vấn đề [bảo mật] được nêu ở đây sẽ biến mất khi chỉ sử dụng UTF-8, đây là một trong nhiều lý do hiện là mã hóa bắt buộc cho tất cả mọi thứ.

Các nhóm khác đang nói như vậy.

Vì vậy, trong khi UTF-16 có thể tiếp tục được sử dụng nội bộ bởi một số hệ thống như Java và Windows, thì việc sử dụng UTF-16 mà bạn có thể thấy trước đây đối với các tệp dữ liệu, trao đổi dữ liệu và có thể sẽ biến mất hoàn toàn.


4

Điều này không liên quan đến UTF-8/16 (nói chung, mặc dù nó chuyển đổi thành UTF16 và phần BE / LE có thể được đặt w / một dòng đơn), nhưng dưới đây là cách nhanh nhất để chuyển Chuỗi thành byte []. Ví dụ: tốt chính xác cho trường hợp được cung cấp (mã băm). String.getBytes (enc) tương đối chậm.

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }

-2

Cách đơn giản để phân biệt UTF-8 và UTF-16 là xác định điểm tương đồng giữa chúng.

Khác với việc chia sẻ cùng một số unicode cho ký tự đã cho, mỗi ký tự là định dạng riêng.

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.