UTF-16 có nên được coi là có hại?


432

Tôi sẽ hỏi điều gì có lẽ là một câu hỏi gây tranh cãi: "Liệu một trong những mã hóa phổ biến nhất, UTF-16, có được coi là có hại không?"

Tại sao tôi hỏi câu hỏi này?

Có bao nhiêu lập trình viên nhận thức được thực tế rằng UTF-16 thực sự là một mã hóa có độ dài thay đổi? Điều này có nghĩa là có những điểm mã, được biểu diễn dưới dạng cặp thay thế, lấy nhiều hơn một phần tử.

Tôi biết; Rất nhiều ứng dụng, khung và API sử dụng UTF-16, chẳng hạn như Chuỗi của Java, Chuỗi của C #, API Win32, thư viện GUI Qt, thư viện Unicode của ICU, v.v. trong số các ký tự ngoài BMP (các ký tự nên được mã hóa bằng hai phần tử UTF-16).

Ví dụ: cố gắng chỉnh sửa một trong các ký tự sau:

Bạn có thể bỏ lỡ một số, tùy thuộc vào phông chữ bạn đã cài đặt. Các ký tự này đều nằm ngoài BMP (Mặt phẳng đa ngôn ngữ cơ bản). Nếu bạn không thể nhìn thấy các ký tự này, bạn cũng có thể thử xem chúng trong tham chiếu Ký tự Unicode .

Ví dụ: cố gắng tạo tên tệp trong Windows bao gồm các ký tự này; hãy thử xóa các ký tự này bằng "backspace" để xem cách chúng hoạt động trong các ứng dụng khác nhau sử dụng UTF-16. Tôi đã làm một số xét nghiệm và kết quả khá tệ:

  • Opera có vấn đề với việc chỉnh sửa chúng (xóa 2 lần nhấn trên backspace)
  • Notepad không thể xử lý chúng một cách chính xác (xóa 2 lần nhấn trên backspace)
  • Chỉnh sửa tên tệp trong hộp thoại Window bị hỏng (xóa 2 lần nhấn trên backspace)
  • Tất cả các ứng dụng QT3 không thể xử lý chúng - hiển thị hai ô vuông trống thay vì một biểu tượng.
  • Python mã hóa các ký tự như vậy không chính xác khi được sử dụng trực tiếp u'X'!=unicode('X','utf-16')trên một số nền tảng khi X trong ký tự bên ngoài BMP.
  • Python 2.5 unicodingata không nhận được các thuộc tính trên các ký tự như vậy khi python được biên dịch bằng chuỗi Unicode UTF-16.
  • StackOverflow dường như loại bỏ các ký tự này khỏi văn bản nếu được chỉnh sửa trực tiếp dưới dạng các ký tự Unicode (các ký tự này được hiển thị bằng cách sử dụng mã HTML Unicode).
  • WinForms TextBox có thể tạo chuỗi không hợp lệ khi bị giới hạn với MaxLạng.

Có vẻ như các lỗi như vậy cực kỳ dễ tìm thấy trong nhiều ứng dụng sử dụng UTF-16.

Vậy ... Bạn có nghĩ rằng UTF-16 nên được coi là có hại không?


64
Không thực sự đúng. Tôi giải thích, nếu bạn viết "" ký tự ghép bao gồm "", "" và "", vovels, sau đó loại bỏ từng ký tự là hợp lý, bạn xóa một điểm mã khi bạn nhấn " backspace "và xóa tất cả các ký tự bao gồm cả vovels khi nhấn" del ". Tuy nhiên, bạn không bao giờ sản xuất bất hợp pháp nhà nước của văn bản - điểm mã bất hợp pháp. Do đó, tình huống khi bạn nhấn backspace và nhận văn bản không hợp lệ là không chính xác.

41
CiscoIPPhone: Nếu một lỗi được "báo cáo nhiều lần, bởi nhiều người khác nhau", và một vài năm sau đó, một nhà phát triển viết trên blog dev rằng "Tin hay không, hành vi chủ yếu là cố ý!", Sau đó (để đặt nó nhẹ nhàng) Tôi có xu hướng nghĩ rằng nó có thể không phải là quyết định thiết kế tốt nhất từng được đưa ra. :-) Chỉ vì nó cố ý không có nghĩa là nó không phải là lỗi.

145
Bài đăng tuyệt vời. UTF-16 thực sự là "tồi tệ nhất của cả hai thế giới": UTF8 có độ dài thay đổi, bao gồm tất cả Unicode, yêu cầu một thuật toán chuyển đổi đến và từ các mật mã thô, hạn chế đối với ASCII và nó không có vấn đề về tuổi thọ. UTF32 có độ dài cố định, không yêu cầu chuyển đổi, nhưng chiếm nhiều không gian hơn và có vấn đề về tuổi thọ. Cho đến nay rất tốt, bạn có thể sử dụng UTF32 trong nội bộ và UTF8 để tuần tự hóa. Nhưng UTF16 không có lợi ích: Nó phụ thuộc vào endian, nó có độ dài thay đổi, cần nhiều không gian, không tương thích ASCII. Nỗ lực cần thiết để đối phó với UTF16 đúng cách có thể được chi tiêu tốt hơn cho UTF8.
Kerrek SB

26
@Ian: UTF-8 KHÔNG có cùng cảnh báo với UTF-8. Bạn không thể có người thay thế trong UTF-8. UTF-8 không giả trang thành một cái gì đó không phải, nhưng hầu hết các lập trình viên sử dụng UTF-16 đều sử dụng sai. Tôi biết. Tôi đã xem chúng nhiều lần và nhiều lần.
tchrist

18
Ngoài ra, UTF-8 không có vấn đề gì vì mọi người đều coi nó là mã hóa chiều rộng thay đổi. Lý do UTF-16 có vấn đề là bởi vì mọi người đều coi nó như một mã hóa chiều rộng cố định.
Christoffer Hammarström

Câu trả lời:


340

Đây là một câu trả lời cũ.
Xem UTF-8 ở mọi nơi để cập nhật mới nhất.

Ý kiến: Có, UTF-16 nên được coi là có hại . Lý do chính nó tồn tại là bởi vì một thời gian trước đây đã từng có một niềm tin sai lầm rằng widechar sẽ là những gì UCS-4 bây giờ là.

Mặc dù "chủ nghĩa trung tâm" của UTF-8, nó nên được coi là mã hóa hữu ích duy nhất cho văn bản. Người ta có thể lập luận rằng mã nguồn của các chương trình, trang web và tệp XML, tên tệp hệ điều hành và các giao diện văn bản từ máy tính đến máy tính khác không bao giờ tồn tại. Nhưng khi họ làm, văn bản không chỉ dành cho độc giả của con người.

Mặt khác, chi phí UTF-8 là một cái giá nhỏ phải trả trong khi nó có lợi thế đáng kể. Các ưu điểm như khả năng tương thích với mã không biết chỉ chuyển qua chuỗi char*. Đây là một điều tuyệt vời. Có một vài ký tự hữu ích được SHORTER trong UTF-16 so với UTF-8.

Tôi tin rằng tất cả các mã hóa khác cuối cùng sẽ chết. Điều này liên quan đến việc MS-Windows, Java, ICU, python ngừng sử dụng nó làm mục ưa thích của họ. Sau thời gian dài nghiên cứu và thảo luận, các quy ước phát triển tại công ty của tôi cấm sử dụng UTF-16 ở bất cứ đâu ngoại trừ các lệnh gọi API OS và điều này mặc dù tầm quan trọng của hiệu suất trong các ứng dụng của chúng tôi và thực tế là chúng tôi sử dụng Windows. Các chức năng chuyển đổi đã được phát triển để chuyển đổi các UTF8 luôn được giả định std::stringthành UTF-16 gốc, bản thân Windows không hỗ trợ đúng cách .

Đối với những người nói " sử dụng những gì cần thiết khi cần thiết ", tôi nói: có một lợi thế rất lớn để sử dụng cùng một mã hóa ở mọi nơi và tôi thấy không có đủ lý do để làm khác. Cụ thể, tôi nghĩ rằng việc thêm wchar_tvào C ++ là một sai lầm và các bổ sung Unicode cho C ++ 0x cũng vậy. Điều phải được yêu cầu từ việc triển khai STL là mọi thông số std::stringhoặc char*tham số sẽ được coi là tương thích unicode.

Tôi cũng chống lại phương pháp " sử dụng những gì bạn muốn ". Tôi thấy không có lý do cho sự tự do như vậy. Có đủ sự nhầm lẫn về chủ đề của văn bản, dẫn đến tất cả các phần mềm bị hỏng này. Ở trên đã nói, tôi tin rằng các lập trình viên cuối cùng phải đạt được sự đồng thuận về UTF-8 như một cách thích hợp. (Tôi đến từ một quốc gia không nói tiếng ascii và lớn lên trên Windows, vì vậy tôi được mong đợi cuối cùng sẽ tấn công UTF-16 dựa trên cơ sở tôn giáo).

Tôi muốn chia sẻ thêm thông tin về cách tôi thực hiện văn bản trên Windows và những gì tôi khuyên mọi người khác để kiểm tra tính chính xác của unicode được kiểm tra thời gian biên dịch, dễ sử dụng và mã đa nền tảng tốt hơn. Gợi ý về cơ bản khác với những gì thường được đề xuất là cách sử dụng Unicode thích hợp trên các cửa sổ. Tuy nhiên, nghiên cứu sâu về các khuyến nghị này dẫn đến kết luận tương tự. Vì vậy, ở đây đi:

  • Không sử dụng wchar_thoặc std::wstringở bất kỳ nơi nào khác ngoài điểm liền kề với API chấp nhận UTF-16.
  • Không sử dụng _T("")hoặc L""UTF-16 lít (Những IMO này nên được đưa ra khỏi tiêu chuẩn, như là một phần của khấu hao UTF-16).
  • Không sử dụng các loại, hàm hoặc các dẫn xuất của chúng nhạy với _UNICODEhằng số, chẳng hạn như LPTSTRhoặc CreateWindow().
  • Tuy nhiên, _UNICODEluôn được xác định, để tránh truyền char*chuỗi cho WinAPI được biên dịch âm thầm
  • std::stringschar*bất cứ nơi nào trong chương trình được coi là UTF-8 (nếu không nói khác)
  • Tất cả các chuỗi của tôi là std::string, mặc dù bạn có thể chuyển char * hoặc chuỗi bằng chữ convert(const std::string &).
  • chỉ sử dụng các hàm Win32 chấp nhận widechars ( LPWSTR). Không bao giờ những người chấp nhận LPTSTRhoặc LPSTR. Truyền tham số theo cách này:

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())
    

    (Chính sách sử dụng các chức năng chuyển đổi bên dưới.)

  • Với dây MFC:

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
    
  • Làm việc với các tệp, tên tệp và luồng trên Windows:

    • Không bao giờ vượt qua std::stringhoặc const char*tên tệp đối số cho fstreamgia đình. MSVC STL không hỗ trợ các đối số UTF-8, nhưng có phần mở rộng không chuẩn nên được sử dụng như sau:
    • Chuyển đổi std::stringđối số std::wstringvới Utils::Convert:

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |
                        std::ios_base::binary);
      

      Chúng tôi sẽ phải xóa thủ công khi chuyển đổi khi thái độ của MSVC fstreamthay đổi.

    • Mã này không phải là đa nền tảng và có thể phải thay đổi bằng tay trong tương lai
    • Xem fstreamtrường hợp nghiên cứu / thảo luận unicode 4215 để biết thêm.
    • Không bao giờ tạo tệp xuất văn bản có nội dung không phải UTF8
    • Tránh sử dụng fopen()vì lý do RAII / OOD. Nếu cần thiết, sử dụng _wfopen()và các quy ước WinAPI ở trên.

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

// Interface to MFC
std::string convert(const CString &mfcString)
{
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
#else
    return mfcString.GetString();   // This branch is deprecated.
#endif
}

CString convert(const std::string &s)
{
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
#else
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
#endif
}

39
Tôi không thể đồng ý. Những lợi thế của utf16 so với utf8 đối với nhiều ngôn ngữ châu Á hoàn toàn thống trị các điểm bạn thực hiện. Thật ngây thơ khi hy vọng rằng người Nhật, Thái Lan, Trung Quốc, v.v ... sẽ từ bỏ mã hóa này. Các cuộc đụng độ có vấn đề giữa các bộ ký tự là khi các bộ ký tự hầu như có vẻ giống nhau, ngoại trừ sự khác biệt. Tôi đề nghị tiêu chuẩn hóa về: 7bit cố định: iso-irv-170; Biến 8 bit: utf8; Biến 16 bit: utf16; Cố định 32 bit: ucs4.

82
@Charles: cảm ơn cho đầu vào của bạn. Đúng, một số ký tự BMP dài hơn trong UTF-8 so với UTF-16. Nhưng, hãy đối mặt với nó: vấn đề không nằm ở byte mà các ký tự Trung Quốc BMP lấy, mà là sự phức tạp trong thiết kế phần mềm phát sinh. Nếu một lập trình viên Trung Quốc phải thiết kế các ký tự có độ dài thay đổi, có vẻ như UTF-8 vẫn là một cái giá nhỏ phải trả so với các biến khác trong hệ thống. Anh ta có thể sử dụng UTF-16 làm thuật toán nén nếu không gian rất quan trọng, nhưng ngay cả khi đó nó sẽ không phù hợp với LZ, và sau LZ hoặc nén chung khác đều có cùng kích thước và entropy.

32
Về cơ bản, điều tôi nói là sự đơn giản hóa được cung cấp bằng cách có một mã hóa cũng tương thích với các chương trình char * hiện có và cũng là phổ biến nhất hiện nay cho mọi thứ là không thể tưởng tượng được. Nó gần giống như trong những ngày "cũ" tốt. Bạn muốn mở một tập tin với một tên? Không cần quan tâm bạn đang làm loại unicode nào, v.v. Tôi đề nghị chúng tôi, các nhà phát triển, giới hạn UTF-16 cho các trường hợp tối ưu hóa rất đặc biệt trong đó một chút hiệu suất đáng giá trong nhiều tháng làm việc.

17
Linux đã có một yêu cầu cụ thể khi chọn sử dụng UTF-8 trong nội bộ: khả năng tương thích với Unix. Windows không cần điều đó, và do đó, khi các nhà phát triển triển khai Unicode, họ đã thêm các phiên bản UCS-2 của hầu hết tất cả các chức năng xử lý văn bản và làm cho các đa nhân đơn giản chuyển đổi thành UCS-2 và gọi các phiên bản khác. Sau đó, họ thay thế UCS-2 bằng UTF-16. Mặt khác, Linux giữ các mã hóa 8 bit và do đó đã sử dụng UTF-8, vì đó là lựa chọn thích hợp trong trường hợp đó.
Mircea Chirea

34
@Pavel Radzivilovsky: BTW, bài viết của bạn về "Tôi tin rằng tất cả các mã hóa khác cuối cùng sẽ chết. Điều này liên quan đến việc MS-Windows, Java, ICU, python ngừng sử dụng nó làm mục ưa thích của họ." "Đặc biệt, tôi nghĩ rằng việc thêm wchar_t vào C ++ là một sai lầm và các bổ sung unicode cho C ++ Ox cũng vậy." hoặc là khá ngây thơ hoặc rất rất kiêu ngạo. Và điều này đến từ một người viết mã tại nhà với Linux và hài lòng với ký tự UTF-8. Nói một cách thẳng thắn: Nó sẽ không xảy ra .
paercebal

157

Mật mã Unicode không phải là ký tự! Đôi khi chúng thậm chí không phải là glyphs (hình thức trực quan).

Vài ví dụ:

  • Mật mã số La Mã như "". (Một ký tự đơn trông giống như "iii".)
  • Các ký tự có dấu như "á", có thể được biểu thị dưới dạng một ký tự kết hợp duy nhất "\ u00e1" hoặc một ký tự và dấu phụ riêng biệt "\ u0061 \ u0301".
  • Các ký tự như sigma chữ thường Hy Lạp, có các hình thức khác nhau cho giữa ("") và kết thúc ("") của các vị trí từ, nhưng nên được coi là từ đồng nghĩa cho tìm kiếm.
  • Dấu gạch nối tùy ý Unicode U + 00AD, có thể hiển thị hoặc không hiển thị trực quan, tùy thuộc vào ngữ cảnh và được bỏ qua cho tìm kiếm ngữ nghĩa.

Cách duy nhất để có quyền chỉnh sửa Unicode là sử dụng thư viện được viết bởi một chuyên gia hoặc trở thành một chuyên gia và tự viết. Nếu bạn chỉ đang đếm mật mã, bạn đang sống trong tình trạng tội lỗi.


19
Điều này. Rất nhiều điều này. UTF-16 có thể gây ra sự cố, nhưng ngay cả khi sử dụng UTF-32 trong suốt thời gian có thể (và sẽ) vẫn cung cấp cho bạn các sự cố.
bcat

11
Một nhân vật là gì? Bạn có thể định nghĩa một điểm mã là một ký tự và nhận được khá nhiều chỉ là tốt. Nếu bạn có nghĩa là một glyph người dùng có thể nhìn thấy, đó là một cái gì đó khác.
tchrist

7
@tchrist chắc chắn để phân bổ không gian mà định nghĩa là tốt, nhưng cho bất cứ điều gì khác? Không nhiều lắm. Nếu bạn xử lý một ký tự kết hợp thành một ký tự duy nhất (nghĩa là cho thao tác xóa hoặc "lấy N ký tự đầu tiên"), bạn sẽ có hành vi lạ và sai. Nếu một điểm mã chỉ có ý nghĩa khi được kết hợp với ít nhất một điểm khác, bạn không thể tự xử lý nó theo bất kỳ cách hợp lý nào.
Voo

6
@Pacerier, đây là bữa tiệc muộn, nhưng tôi phải bình luận về điều đó. Một số ngôn ngữ có các tập hợp tiềm năng rất lớn của dấu phụ (cf tiếng Việt, tức là từ đừ). Có sự kết hợp chứ không phải là một ký tự cho mỗi dấu phụ là rất hữu ích.
asthasr

21
một lưu ý nhỏ về thuật ngữ: codepoints làm tương ứng với các ký tự unicode ; những gì Daniel đang nói ở đây là các ký tự được người dùng cảm nhận , tương ứng với các cụm grapheme unicode
Christoph

54

Có một quy tắc đơn giản về việc sử dụng Biểu mẫu chuyển đổi Unicode (UTF) nào: - utf-8 để lưu trữ và kết hợp - utf-16 để xử lý dữ liệu - bạn có thể sử dụng utf-32 nếu hầu hết API nền tảng bạn sử dụng là utf-32 (phổ biến trong thế giới UNIX).

Hầu hết các hệ thống ngày nay sử dụng utf-16 (Windows, Mac OS, Java, .NET, ICU, Qt). Cũng xem tài liệu này: http://unicode.org/notes/tn12/

Quay lại "UTF-16 là có hại", tôi sẽ nói: chắc chắn là không.

Những người sợ thay thế (nghĩ rằng họ chuyển đổi Unicode thành mã hóa có độ dài thay đổi) không hiểu được các phức tạp (cách lớn hơn) khác khiến việc ánh xạ giữa các ký tự và điểm mã Unicode rất phức tạp: kết hợp các ký tự, chữ ghép, bộ chọn biến thể , điều khiển nhân vật, v.v.

Chỉ cần đọc loạt bài này ở đây http://www.siao2.com/2009/06/29/9800913.aspx và xem UTF-16 trở thành một vấn đề dễ dàng như thế nào.


26
Vui lòng thêm một số ví dụ trong đó UTF-32 phổ biến trong thế giới UNIX!
maxschlepzig

48
Không, bạn không muốn sử dụng UTF-16 để xử lý dữ liệu. Đó là một cơn đau ở mông. Nó có tất cả các nhược điểm của UTF-8 nhưng không có ưu điểm nào. Cả UTF-8 và UTF-32 rõ ràng đều vượt trội so với vụ hack độc ác trước đây được biết đến với tên gọi Bà UTF-16, có tên thời con gái là UCS-2.
tchrist

34
Hôm qua tôi vừa tìm thấy một lỗi trong equalsIgnoreCasephương thức của lớp Chuỗi lõi Java (cũng là một lỗi khác trong lớp chuỗi) mà Java chưa từng sử dụng hoặc UTF-8 hoặc UTF-32. Có hàng triệu quả bom ngủ này trong bất kỳ mã nào sử dụng UTF-16, và tôi phát ốm và mệt mỏi với chúng. UTF-16 là một loại thuốc độc hại làm hỏng phần mềm của chúng ta với các lỗi ngấm ngầm mãi mãi. Nó rõ ràng có hại, và nên được phản đối và bị cấm.
tchrist

7
@tchrist Wow một chức năng nhận biết không thay thế (bởi vì nó được viết khi không có và được ghi lại một cách đáng buồn theo cách khiến nó có thể không thích ứng - nó chỉ định .toUpperCase (char)) sẽ dẫn đến hành vi sai? Bạn có biết rằng một hàm UTF-32 với bản đồ điểm mã lỗi thời sẽ không xử lý việc này tốt hơn không? Ngoài ra, toàn bộ API Java xử lý các thay thế không đặc biệt tốt và các điểm phức tạp hơn về Unicode hoàn toàn không - và với việc mã hóa được sử dụng sau này hoàn toàn không thành vấn đề.
Voo

8
-1: Một điều kiện vô điều kiện .Substring(1)trong .NET là một ví dụ tầm thường về một cái gì đó phá vỡ sự hỗ trợ cho tất cả các Unicode không phải BMP. Mọi thứ sử dụng UTF-16 đều có vấn đề này; quá dễ dàng để coi nó như một mã hóa có chiều rộng cố định và bạn hiếm khi gặp vấn đề. Điều đó làm cho nó trở thành một mã hóa có hại tích cực nếu bạn muốn hỗ trợ Unicode.
Roman Starkov

43

Chắc chắn rồi.

Tại sao? Nó phải làm với việc thực hiện mã .

Nếu bạn xem các số liệu thống kê sử dụng tiền mã hóa trên một kho dữ liệu lớn của Tom Christiansen, bạn sẽ thấy rằng các loại tiền mã hóa BMP 8 bit được sử dụng một số đơn đặt hàng nếu cường độ lớn hơn các loại tiền mã hóa không phải BMP:

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE

 544 U+01D49E ‹𝒞›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL C
 450 U+01D4AF ‹𝒯›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL T
 385 U+01D4AE ‹𝒮›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL S
 292 U+01D49F ‹𝒟›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL D
 285 U+01D4B3 ‹𝒳›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL X

Lấy câu lệnh TDD: "Mã chưa được kiểm tra là mã bị hỏng" và viết lại mã đó là "mã không được mã hóa là mã bị hỏng" và nghĩ rằng các lập trình viên thường phải xử lý các mật mã không phải BMP như thế nào.

Các lỗi liên quan đến việc không xử lý UTF-16 như một mã hóa có chiều rộng thay đổi có nhiều khả năng không được chú ý hơn các lỗi tương đương trong UTF-8 . Một số ngôn ngữ lập trình vẫn không đảm bảo cung cấp cho bạn UTF-16 thay vì UCS-2 và một số ngôn ngữ lập trình cấp cao cung cấp quyền truy cập vào các đơn vị mã thay vì điểm mã (thậm chí C được cho là cung cấp cho bạn quyền truy cập vào tiền mã hóa nếu bạn sử dụng wchar_t, bất kể một số nền tảng có thể làm gì).


16
"Các lỗi liên quan đến việc không xử lý UTF-16 như một mã hóa có chiều rộng thay đổi có nhiều khả năng không được chú ý hơn các lỗi tương đương trong UTF-8." Đây là cốt lõi của vấn đề, và do đó, câu trả lời chính xác.
Sean McMillan

3
Đúng. Nếu việc xử lý UTF-8 của bạn bị hỏng, điều đó sẽ rõ ràng ngay lập tức. Nếu việc xử lý UTF-8 của bạn bị hỏng, bạn sẽ chỉ chú ý nếu bạn đặt các ký tự chữ Hán hoặc ký hiệu toán học không phổ biến.
Ốc cơ khí

1
Rất đúng, nhưng mặt khác, các bài kiểm tra đơn vị là gì nếu bạn nên phụ thuộc vào may mắn để tìm ra lỗi trong các trường hợp ít thường xuyên hơn?
musiphil

@musiphil: vậy, lần cuối cùng bạn tạo một bài kiểm tra đơn vị cho các ký tự không phải BMP là khi nào?
ninjalj

1
Để giải thích về tuyên bố trước đây của tôi: ngay cả với UTF-8, bạn không thể yên tâm rằng bạn đã bao gồm tất cả các trường hợp sau khi chỉ nhìn thấy một số ví dụ hoạt động. Tương tự với UTF-16: bạn cần kiểm tra xem mã của bạn có hoạt động cả với người không thay thế và người thay thế hay không. (Ai đó thậm chí có thể lập luận rằng UTF-8 có ít nhất bốn trường hợp chính trong khi UTF-16 chỉ có hai.)
musiphil

40

Tôi muốn đề xuất rằng suy nghĩ UTF-16 có thể được coi là có hại nói rằng bạn cần hiểu rõ hơn về unicode .

Vì tôi đã bị hạ thấp vì trình bày ý kiến ​​của mình về một câu hỏi chủ quan, hãy để tôi giải thích. Chính xác thì điều gì làm phiền bạn về UTF-16? Bạn có thích nếu mọi thứ được mã hóa trong UTF-8? UTF-7? Hay làm thế nào về UCS-4? Tất nhiên một số ứng dụng nhất định không được thiết kế để xử lý mã ký tự everysingle ngoài kia - nhưng chúng là cần thiết, đặc biệt là trong miền thông tin toàn cầu ngày nay, để liên lạc giữa các ranh giới quốc tế.

Nhưng thực sự, nếu bạn cảm thấy UTF-16 nên được coi là có hại vì nó gây nhầm lẫn hoặc có thể được thực hiện không đúng cách (unicode chắc chắn có thể), vậy phương pháp mã hóa ký tự nào sẽ được coi là không có hại?

EDIT: Để làm rõ: Tại sao xem xét việc triển khai không đúng tiêu chuẩn phản ánh chất lượng của chính tiêu chuẩn? Như những người khác đã lưu ý sau đó, chỉ vì một ứng dụng sử dụng một công cụ không phù hợp, không có nghĩa là chính công cụ đó bị lỗi. Nếu đó là trường hợp, có lẽ chúng ta có thể nói những điều như "từ khóa var được coi là có hại" hoặc "luồng được coi là có hại". Tôi nghĩ rằng câu hỏi nhầm lẫn giữa chất lượng và bản chất của tiêu chuẩn với những khó khăn mà nhiều lập trình viên gặp phải khi thực hiện và sử dụng nó đúng cách, điều mà tôi cảm thấy xuất phát từ việc họ không hiểu cách thức hoạt động của unicode, thay vì unicode.


33
-1: Làm thế nào về việc giải quyết một số phản đối của Artyom, thay vì chỉ bảo trợ anh ta?

8
BTW: Khi tôi bắt đầu viết bài viết này, tôi gần như muốn viết "Có phải Joel trên Softeare bài viết về Unicode có bị coi là có hại không" vì có nhiều sai lầm. Ví dụ: mã hóa utf-8 có tối đa 4 ký tự chứ không phải 6. Ngoài ra, nó không phân biệt giữa UCS-2 và UTF-16 thực sự khác nhau - và thực sự gây ra các vấn đề tôi nói.

32
Ngoài ra, cần lưu ý rằng khi Joel viết bài báo đó, tiêu chuẩn UTF-8 WAS 6 byte, chứ không phải 4. RFC 3629 đã thay đổi tiêu chuẩn thành 4 byte vài tháng sau khi anh ấy viết bài báo. Giống như hầu hết mọi thứ trên internet, nó trả tiền để đọc từ nhiều nguồn và để nhận biết tuổi của các nguồn của bạn. Liên kết không nhằm mục đích "kết thúc tất cả là tất cả", mà là điểm bắt đầu.

7
Tôi sẽ pic: utf-8 hoặc utf-32 đó là: mã hóa độ dài thay đổi trong hầu hết các trường hợp (bao gồm BMP) hoặc mã hóa độ dài cố định luôn.

18
@iconiK: Đừng ngớ ngẩn. UTF-16 hoàn toàn không phải là tiêu chuẩn thực tế để xử lý văn bản. Chỉ cho tôi một ngôn ngữ lập trình phù hợp hơn với xử lý văn bản mà Perl, người luôn luôn (tốt, trong hơn một thập kỷ) đã sử dụng các ký tự trừu tượng với biểu diễn UTF-8 bên trong. Bởi vì điều này, mọi chương trình Perl sẽ tự động xử lý tất cả Unicode mà người dùng không phải liên tục làm phiền với những người thay thế ngu ngốc. Độ dài của một chuỗi là số đếm của nó trong các điểm mã, không phải đơn vị mã. Bất cứ điều gì khác là sự ngu ngốc tuyệt đối đưa sự tương thích ngược trở lại.
tchrist

37

Không có gì sai với mã hóa Utf-16. Nhưng các ngôn ngữ coi các đơn vị 16 bit là ký tự có lẽ nên được coi là thiết kế tồi. Có một loại có tên ' char' mà không phải lúc nào cũng đại diện cho một nhân vật là khá khó hiểu. Vì hầu hết các nhà phát triển sẽ mong đợi một loại char đại diện cho một điểm mã hoặc ký tự, nhiều mã có thể sẽ bị phá vỡ khi tiếp xúc với các ký tự BMP.

Tuy nhiên, lưu ý rằng ngay cả khi sử dụng utf-32 không có nghĩa là mỗi điểm mã 32 bit sẽ luôn đại diện cho một ký tự. Do kết hợp các ký tự, một ký tự thực tế có thể bao gồm một số điểm mã. Unicode không bao giờ là tầm thường.

BTW. Có lẽ có cùng một loại lỗi với các nền tảng và ứng dụng dự kiến ​​các ký tự là 8 bit, được cho ăn Utf-8.


12
Trong trường hợp của Java, nếu bạn nhìn vào dòng thời gian của họ ( java.com/en/javahistory/timeline.jsp ), bạn sẽ thấy rằng sự phát triển chủ yếu của String đã xảy ra trong khi Unicode là 16 bit (nó đã thay đổi vào năm 1996). Họ đã phải tăng cường khả năng xử lý các điểm mã BMP, do đó gây nhầm lẫn.
Kathy Van Stone

10
@Kathy: Mặc dù không thực sự là một cái cớ cho C #. Nói chung, tôi đồng ý rằng cần có một CodePointloại, giữ một điểm mã duy nhất (21 bit), một CodeUnitloại, giữ một đơn vị mã duy nhất (16 bit cho UTF-16) và một Characterloại lý tưởng sẽ phải hỗ trợ một đồ thị hoàn chỉnh. Nhưng điều đó làm cho nó có chức năng tương đương với một String...
Joey

1
Câu trả lời này đã gần hai năm, nhưng tôi không thể không bình luận về nó. "Có một loại tên là 'char' mà không phải lúc nào cũng đại diện cho một nhân vật là khá khó hiểu." Tuy nhiên, mọi người sử dụng nó mọi lúc trong C và muốn đại diện cho dữ liệu số nguyên có thể được lưu trữ trong một byte đơn.
JAB

Và tôi đã thấy rất nhiều mã C không xử lý mã hóa ký tự chính xác.
dan04

1
C # có một lý do khác: nó được thiết kế cho Windows và Windows được xây dựng trên UCS-2 (rất khó chịu khi ngay cả ngày nay các API Windows không thể hỗ trợ UTF-8). Thêm vào đó, tôi nghĩ rằng Microsoft muốn tương thích Java (.NET 1.0 có thư viện tương thích Java, nhưng họ đã bỏ hỗ trợ Java rất nhanh - Tôi đoán đây là do vụ kiện của Sun chống lại MS?)
Qwertie

20

Lựa chọn cá nhân của tôi là luôn sử dụng UTF-8. Đó là tiêu chuẩn trên Linux cho hầu hết mọi thứ. Nó tương thích ngược với nhiều ứng dụng cũ. Có một chi phí rất nhỏ về không gian thêm được sử dụng cho các ký tự không phải là tiếng Latin so với các định dạng UTF khác và có một khoản tiết kiệm đáng kể trong không gian cho các ký tự Latin. Trên trang web, các ngôn ngữ Latin trị vì tối cao, và tôi nghĩ chúng sẽ cho tương lai gần. Và để giải quyết một trong những đối số chính trong bài viết gốc: gần như mọi lập trình viên đều biết rằng UTF-8 đôi khi sẽ có các ký tự nhiều byte trong đó. Không phải ai cũng giải quyết vấn đề này một cách chính xác, nhưng họ thường nhận thức được, điều này có thể nói nhiều hơn về UTF-16. Nhưng, tất nhiên, bạn cần chọn một ứng dụng phù hợp nhất cho ứng dụng của bạn. Đó là lý do tại sao có nhiều hơn một ở nơi đầu tiên.


3
UTF-16 đơn giản hơn cho mọi thứ trong BMP, đó là lý do tại sao nó được sử dụng rộng rãi. Nhưng tôi cũng là một fan hâm mộ của UTF-8, nó cũng không có vấn đề gì với thứ tự byte, hoạt động theo lợi thế của nó.
Malcolm

2
Về mặt lý thuyết, có. Trong thực tế, có những thứ như, giả sử, UTF-16BE, có nghĩa là UTF-16 theo nghĩa lớn không có BOM. Đây không phải là thứ tôi tạo ra, đây là một mã hóa thực tế được phép trong các thẻ ID3v2.4 (thẻ ID3v2 hút, nhưng, thật không may, được sử dụng rộng rãi). Và trong những trường hợp như vậy, bạn phải xác định tuổi thọ bên ngoài, vì bản thân văn bản không chứa BOM. UTF-8 luôn được viết một chiều và nó không có vấn đề như vậy.
Malcolm

23
Không, UTF-16 không đơn giản. Nó khó hơn Nó đánh lừa và đánh lừa bạn nghĩ rằng nó là chiều rộng cố định. Tất cả các mã như vậy đã bị hỏng và tất cả các moreso vì bạn không nhận thấy cho đến khi quá muộn. TRƯỜNG HỢP TRONG ĐIỂM: Tôi vừa tìm thấy một lỗi UTF-16 ngu ngốc khác trong các thư viện lõi Java ngày hôm qua, lần này là trong String.equalsIgnoreCase, đã bị bỏ lại trong chương trình bẻ khóa UCS-2, và do đó đã thất bại ở 16/17 điểm mã Unicode hợp lệ. Mã đó đã tồn tại bao lâu rồi? Không có lý do gì để nó bị lỗi. UTF-16 dẫn đến sự ngu ngốc và một tai nạn đang chờ xảy ra. Chạy la hét từ UTF-16.
tchrist

3
@tchrist Một người phải là một nhà phát triển rất thiếu hiểu biết để không biết rằng UTF-16 không có chiều dài cố định. Nếu bạn bắt đầu với Wikipedia, bạn sẽ đọc phần sau ở trên cùng: "Nó tạo ra kết quả có độ dài thay đổi của một hoặc hai đơn vị mã 16 bit cho mỗi điểm mã". Câu hỏi thường gặp về Unicode cũng nói như vậy: unicode.org/faq//utf_bom.html#utf16-1 . Tôi không biết, làm thế nào UTF-16 có thể đánh lừa bất cứ ai nếu nó được viết ở mọi nơi mà nó có độ dài thay đổi. Đối với phương pháp, nó không bao giờ được thiết kế cho UTF-16 và không nên được coi là Unicode, đơn giản như vậy.
Malcolm

2
@tchrist Bạn có nguồn thống kê nào không? Mặc dù nếu lập trình viên giỏi khan hiếm, tôi nghĩ điều này tốt, bởi vì chúng ta trở nên có giá trị hơn. :) Đối với các API Java, các phần dựa trên char cuối cùng có thể bị phản đối, nhưng điều này không đảm bảo rằng chúng sẽ không được sử dụng. Và họ chắc chắn sẽ không bị xóa vì lý do khả năng.
Malcolm

18

Vâng, có một mã hóa sử dụng các ký hiệu kích thước cố định. Tôi chắc chắn có nghĩa là UTF-32. Nhưng 4 byte cho mỗi biểu tượng là quá nhiều không gian lãng phí, tại sao chúng ta sẽ sử dụng nó trong các tình huống hàng ngày?

Theo tôi, hầu hết các vấn đề xuất hiện từ thực tế là một số phần mềm nằm sau tiêu chuẩn Unicode, nhưng không nhanh chóng khắc phục tình trạng này. Opera, Windows, Python, Qt - tất cả chúng đều xuất hiện trước khi UTF-16 được biết đến rộng rãi hoặc thậm chí ra đời. Tuy nhiên, tôi có thể xác nhận rằng trong Opera, Windows Explorer và Notepad không có vấn đề gì với các nhân vật bên ngoài BMP nữa (ít nhất là trên PC của tôi). Nhưng dù sao, nếu các chương trình không nhận ra các cặp thay thế, thì chúng không sử dụng UTF-16. Bất cứ vấn đề nào phát sinh từ việc xử lý các chương trình như vậy, chúng không liên quan gì đến chính UTF-16.

Tuy nhiên, tôi nghĩ rằng các vấn đề của phần mềm cũ chỉ có hỗ trợ BMP là hơi cường điệu. Các nhân vật bên ngoài BMP chỉ gặp phải trong các trường hợp và khu vực rất cụ thể. Theo Câu hỏi thường gặp chính thức về Unicode , "ngay cả trong văn bản Đông Á, tỷ lệ các cặp thay thế phải ở mức trung bình dưới 1% của tất cả lưu trữ văn bản". Tất nhiên, các ký tự bên ngoài BMP không nên bị bỏ qua vì một chương trình không phù hợp với Unicode, nhưng hầu hết các chương trình không dành cho làm việc với các văn bản có chứa các ký tự đó. Đó là lý do tại sao nếu họ không ủng hộ nó, điều đó thật khó chịu, nhưng không phải là một thảm họa.

Bây giờ hãy xem xét sự thay thế. Nếu UTF-16 không tồn tại, thì chúng tôi sẽ không có mã hóa phù hợp với văn bản không phải ASCII và tất cả phần mềm được tạo cho UCS-2 sẽ phải được thiết kế lại hoàn toàn để vẫn tuân thủ Unicode. Cái sau rất có thể sẽ chỉ làm chậm việc áp dụng Unicode. Ngoài ra, chúng tôi sẽ không thể duy trì khả năng tương thích với văn bản trong UCS-2 giống như UTF-8 liên quan đến ASCII.

Bây giờ, đặt tất cả các vấn đề di sản sang một bên, các đối số chống lại chính mã hóa là gì? Tôi thực sự nghi ngờ rằng các nhà phát triển ngày nay không biết rằng UTF-16 có chiều dài thay đổi, nó được viết ở khắp mọi nơi với Wikipedia. UTF-16 khó phân tích cú pháp hơn nhiều so với UTF-8, nếu ai đó chỉ ra sự phức tạp là một vấn đề có thể xảy ra. Ngoài ra, thật sai lầm khi nghĩ rằng thật dễ gây rối khi xác định độ dài chuỗi chỉ trong UTF-16. Nếu bạn sử dụng UTF-8 hoặc UTF-32, bạn vẫn cần lưu ý rằng một điểm mã Unicode không nhất thiết phải có một ký tự. Ngoài ra, tôi không nghĩ rằng có bất cứ điều gì đáng kể chống lại mã hóa.

Vì vậy, tôi không nghĩ rằng bản thân mã hóa nên được coi là có hại. UTF-16 là một sự thỏa hiệp giữa đơn giản và gọn nhẹ, và không có hại trong việc sử dụng những gì cần thiết khi cần thiết . Trong một số trường hợp, bạn cần duy trì khả năng tương thích với ASCII và bạn cần UTF-8, trong một số trường hợp bạn muốn làm việc với các chữ tượng hình Han và bảo tồn không gian bằng UTF-16, trong một số trường hợp, bạn cần biểu diễn phổ biến các ký tự cho phép cố định- mã hóa chiều dài. Sử dụng những gì phù hợp hơn, chỉ cần làm đúng.


21
Đó là một cái nhìn khá chớp mắt, trung tâm Anglo, Malcolm. Gần như ngang tầm với "ASCII là đủ tốt cho Hoa Kỳ - phần còn lại của thế giới sẽ phù hợp với chúng tôi".
Jonathan Leffler

28
Trên thực tế, tôi đến từ Nga và luôn luôn bắt gặp các nhà khoa học (bao gồm cả các chương trình của riêng tôi), vì vậy tôi không nghĩ rằng tôi có quan điểm trung tâm. :) Nhắc đến ASCII không hoàn toàn phù hợp, vì nó không phải là Unicode và không hỗ trợ các ký tự cụ thể. UTF-8, UTF-16, UTF-32 hỗ trợ các bộ ký tự quốc tế rất giống nhau, chúng chỉ nhằm mục đích sử dụng trong các khu vực cụ thể của chúng. Và đây chính xác là quan điểm của tôi: nếu bạn sử dụng chủ yếu là tiếng Anh, hãy sử dụng UTF-8, nếu bạn sử dụng chủ yếu là cyrillics, hãy sử dụng UTF-16, nếu bạn sử dụng ngôn ngữ cổ, hãy sử dụng UTF-32. Khá đơn giản.
Malcolm

16
"Không đúng, các tập lệnh châu Á như Nhật Bản, Trung Quốc hay Ả Rập cũng thuộc về BMP. Bản thân BMP thực sự rất lớn và chắc chắn đủ lớn để bao gồm tất cả các tập lệnh được sử dụng hiện nay" Điều này hoàn toàn sai. BMP chứa các ký tự 0xFFFF (65536). Chỉ riêng người Trung Quốc đã có nhiều hơn thế. Tiêu chuẩn Trung Quốc (GB 18030) có nhiều hơn thế. Unicode 5.1 đã được phân bổ hơn 100.000 ký tự.

12
@Marcolm: "Bản thân BMP thực sự rất lớn và chắc chắn đủ lớn để bao gồm tất cả các tập lệnh được sử dụng hiện nay" Không đúng. Tại thời điểm này, Unicode đã được phân bổ khoảng 100 nghìn ký tự, nhiều hơn BMP có thể chứa được. Có rất nhiều nhân vật Trung Quốc bên ngoài BMP. Và một số trong số chúng được yêu cầu bởi GB-18030 (tiêu chuẩn bắt buộc của Trung Quốc). Khác được yêu cầu theo tiêu chuẩn Nhật Bản và Hàn Quốc (không bắt buộc). Vì vậy, nếu bạn cố gắng bán bất cứ thứ gì trong các thị trường đó, bạn cần ngoài sự hỗ trợ của BMP.

8
Bất cứ điều gì sử dụng UTF-16 nhưng chỉ có thể xử lý các ký tự BMP hẹp không thực sự sử dụng UTF-16. Đó là lỗi và bị hỏng. Tiền đề của OP là âm thanh: UTF-16 có hại, bởi vì nó dẫn những người ngây thơ viết mã bị hỏng. Bạn có thể xử lý văn bản Unicode hoặc không thể. Nếu bạn không thể, thì bạn đang chọn một tập hợp con, điều này cũng ngu ngốc như xử lý văn bản chỉ ASCII.
tchrist

16

Nhiều năm hoạt động quốc tế hóa Windows đặc biệt là các ngôn ngữ Đông Á có thể đã làm hỏng tôi, nhưng tôi nghiêng về UTF-16 để thể hiện các chuỗi nội bộ trong chương trình và UTF-8 để lưu trữ mạng hoặc tệp tài liệu giống như văn bản. UTF-16 thường có thể được xử lý nhanh hơn trên Windows, do đó, đó là lợi ích chính của việc sử dụng UTF-16 trong Windows.

Bước nhảy vọt lên UTF-16 đã cải thiện đáng kể tính đầy đủ của các sản phẩm trung bình xử lý văn bản quốc tế. Chỉ có một vài trường hợp hẹp khi các cặp thay thế cần được xem xét (xóa, chèn và ngắt dòng, về cơ bản) và trường hợp trung bình chủ yếu là truyền thẳng. Và không giống như các mã hóa trước đó như các biến thể JIS, UTF-16 giới hạn các cặp thay thế trong phạm vi rất hẹp, do đó kiểm tra thực sự nhanh chóng và hoạt động tiến và lùi.

Cấp, nó cũng nhanh như vậy trong UTF-8 được mã hóa chính xác, quá. Nhưng cũng có nhiều ứng dụng UTF-8 bị hỏng mã hóa không chính xác các cặp thay thế thành hai chuỗi UTF-8. Vì vậy, UTF-8 cũng không đảm bảo sự cứu rỗi.

IE xử lý các cặp thay thế một cách hợp lý kể từ năm 2000 hoặc lâu hơn, mặc dù nó thường chuyển đổi chúng từ các trang UTF-8 sang một đại diện UTF-16 nội bộ; Tôi khá chắc chắn rằng Firefox cũng đã hiểu đúng, vì vậy tôi không thực sự quan tâm Opera làm gì.

UTF-32 (còn gọi là UCS4) là vô nghĩa đối với hầu hết các ứng dụng vì nó đòi hỏi nhiều không gian, do đó, nó gần như không thông minh.


6
Tôi không nhận được bình luận của bạn về các cặp UTF-8 và thay thế. Các cặp thay thế chỉ là một khái niệm có ý nghĩa trong mã hóa UTF-16, phải không? Có lẽ mã chuyển đổi trực tiếp từ mã hóa UTF-16 sang mã hóa UTF-8 có thể sai, và trong trường hợp đó, vấn đề là đọc sai UTF-16, không viết UTF-8. Có đúng không?
Craig McQueen

11
Điều Jason nói đến là phần mềm cố tình thực hiện UTF-8 theo cách đó: tạo một cặp thay thế, sau đó UTF-8 mã hóa riêng từng nửa. Tên chính xác cho mã hóa đó là CESU-8, nhưng Oracle (ví dụ) trình bày sai nó là UTF-8. Java sử dụng một sơ đồ tương tự để tuần tự hóa đối tượng, nhưng nó được ghi lại rõ ràng là "UTF-8 đã sửa đổi" và chỉ sử dụng nội bộ. (Bây giờ, nếu chúng ta có thể khiến mọi người ĐỌC tài liệu đó và ngừng sử dụng DataInputStream # readUTF () và DataOutputStream # writeUTF () một cách không phù hợp ...)

AFAIK, UTF-32 vẫn là mã hóa độ dài thay đổi và không bằng UCS4 là phạm vi cụ thể của điểm mã.
Eonil

@Eonil, UTF-32 sẽ chỉ có thể phân biệt được với UCS4 nếu chúng ta có một tiêu chuẩn Unicode có tính năng như UCS5 hoặc lớn hơn.
JasonTrue

@JasonTrue Tuy nhiên, chỉ có kết quả trùng khớp ngẫu nhiên, không được đảm bảo bởi thiết kế. Điều tương tự cũng xảy ra trong địa chỉ bộ nhớ 32 bit, Y2K, UTF16 / UCS2. Hay chúng ta có bất kỳ sự đảm bảo về sự bình đẳng đó? Nếu chúng ta có, tôi sẵn sàng sử dụng nó. Nhưng tôi không muốn viết một mã có thể phá vỡ . Tôi đang viết mã cấp độ ký tự và thiếu một cách đảm bảo để chuyển mã giữa UTF <-> điểm mã đang làm phiền tôi rất nhiều.
Eonil

16

UTF-8 chắc chắn là con đường để đi, có thể đi kèm với UTF-32 để sử dụng nội bộ trong các thuật toán cần truy cập ngẫu nhiên hiệu suất cao (nhưng bỏ qua việc kết hợp các ký tự).

Cả UTF-16 và UTF-32 (cũng như các biến thể LE / BE của chúng) đều gặp phải các vấn đề liên quan, vì vậy chúng không bao giờ được sử dụng bên ngoài.


9
Cũng có thể truy cập ngẫu nhiên theo thời gian liên tục với UTF-8, chỉ cần sử dụng các đơn vị mã thay vì điểm mã. Có thể bạn cần truy cập điểm mã ngẫu nhiên thực sự, nhưng tôi chưa bao giờ thấy trường hợp sử dụng và bạn cũng có khả năng muốn truy cập cụm grapheme ngẫu nhiên thay thế.

15

UTF-16? chắc chắn có hại. Chỉ có hạt muối của tôi ở đây, nhưng có chính xác ba mã hóa được chấp nhận cho văn bản trong một chương trình:

  • ASCII: khi xử lý những thứ cấp thấp (ví dụ: vi điều khiển) không thể mua được bất cứ thứ gì tốt hơn
  • UTF8: lưu trữ trong phương tiện có chiều rộng cố định như tệp
  • mã số nguyên ("CP"?): một mảng gồm các số nguyên lớn nhất thuận tiện cho ngôn ngữ lập trình và nền tảng của bạn (phân rã thành ASCII trong giới hạn độ phân giải thấp). Nên là int32 trên các máy tính cũ và int64 trên bất cứ thứ gì có địa chỉ 64 bit.

  • Rõ ràng các giao diện cho mã kế thừa sử dụng mã hóa nào là cần thiết để làm cho mã cũ hoạt động đúng.


4
@simon buchan, U+10ffffmax sẽ đi ra ngoài cửa sổ khi (không nếu) họ hết tiền mã hóa. Điều đó nói rằng, sử dụng int32 trên hệ thống p64 cho tốc độ có thể an toàn, vì tôi nghi ngờ chúng sẽ vượt quá U+fffffffftrước khi bạn buộc phải viết lại mã của mình cho các hệ thống 128 bit vào khoảng năm 2050. (Đó là điểm "sử dụng int lớn nhất mà là tiện lợi "trái ngược với" lớn nhất có sẵn "(có thể là int256 hoặc bignums hoặc một cái gì đó).)
David X

1
@David: Unicode 5.2 mã hóa 107.361 điểm mã. Có 867.169 điểm mã chưa sử dụng. "khi" chỉ là ngớ ngẩn. Một bảng mã Unicode được định nghĩa là một số từ 0 đến 0x10FFFF, một thuộc tính mà UTF-16 phụ thuộc vào. (Ngoài ra, năm 2050 dường như rất thấp để ước tính cho các hệ thống 128 bit khi hệ thống 64 bit có thể chứa toàn bộ Internet trong không gian địa chỉ của nó.)

3
@David: "khi nào" của bạn đề cập đến việc hết tiền mã hóa Unicode, không phải là công tắc 128 bit, vâng, sẽ có trong vài thế kỷ tới. Không giống như bộ nhớ, không có sự tăng trưởng theo cấp số nhân của các ký tự, do đó, Hiệp hội Unicode đã đảm bảo cụ thể rằng họ sẽ không bao giờ phân bổ một mật mã ở trên U+10FFFF. Đây thực sự là một trong những tình huống khi 21 bit đủ cho bất kỳ ai.

10
@Simon Buchan: Ít nhất là cho đến lần tiếp xúc đầu tiên. :)

3
Unicode được sử dụng để đảm bảo rằng sẽ không có điểm mã nào trên U + FFFF.
Shannon Severance

13

Unicode xác định các điểm mã lên tới 0x10FFFF (1.114.112 mã), tất cả các ứng dụng chạy trong môi trường đa ngôn ngữ xử lý các chuỗi / tên tệp, v.v. nên xử lý chính xác.

Utf-16 : chỉ bao gồm 1.112.064 mã. Mặc dù những người ở cuối Unicode là từ các mặt phẳng 15-16 (Khu vực sử dụng riêng). Nó không thể phát triển hơn nữa trong tương lai ngoại trừ phá vỡ khái niệm Utf-16 .

Utf-8 : bao gồm lý thuyết 2.216.757.376 mã. Phạm vi mã Unicode hiện tại có thể được biểu diễn bằng chuỗi 4 byte tối đa. Nó không gặp vấn đề với thứ tự byte , nó "tương thích" với ascii.

Utf-32 : bao gồm trên lý thuyết 2 ^ 32 = 4.294.967.296 mã. Hiện tại nó không được mã hóa chiều dài thay đổi và có thể sẽ không có trong tương lai.

Những sự thật là tự giải thích. Tôi không hiểu ủng hộ việc sử dụng chung của Utf-16 . Nó được mã hóa chiều dài thay đổi (không thể truy cập theo chỉ mục), nó có vấn đề để bao trùm toàn bộ phạm vi Unicode ngay cả hiện tại, thứ tự byte phải được xử lý, v.v. Tôi không thấy bất kỳ lợi thế nào ngoại trừ việc nó được sử dụng trong Windows và một số nơi khác. Mặc dù khi viết mã đa nền tảng, có lẽ tốt hơn là sử dụng Utf-8 nguyên bản và chỉ thực hiện chuyển đổi ở điểm cuối theo cách phụ thuộc nền tảng (như đã đề xuất). Khi cần truy cập trực tiếp theo chỉ mục và bộ nhớ không phải là vấn đề, nên sử dụng Utf-32 .

Vấn đề chính là nhiều lập trình viên xử lý Windows Unicode = Utf-16 thậm chí không biết hoặc bỏ qua thực tế rằng nó được mã hóa theo chiều dài thay đổi.

Cách thức thường có trong nền tảng * nix là khá tốt, chuỗi c (char *) được hiểu là mã hóa Utf-8 , chuỗi c rộng (wchar_t *) được hiểu là Utf-32 .


7
Lưu ý: UTF-16 bao gồm Tất cả Unicode như Unicode Consortium đã quyết định rằng 10FFFF là phạm vi TOP của Unicode và độ dài tối đa 4 byte UTF-8 được xác định và phạm vi loại trừ rõ ràng 0xD800-0xDFFF từ phạm vi điểm mã hợp lệ và phạm vi này được sử dụng để tạo cặp thay thế. Vì vậy, bất kỳ văn bản Unicode hợp lệ nào cũng có thể được trình bày với mỗi một trong những bảng mã này. Cũng về phát triển đến tương lai. Dường như 1 triệu điểm mã sẽ không đủ trong tương lai xa.

7
@Kerrek: Không chính xác: UCS-2 không phải là mã hóa Unicode hợp lệ. Tất cả các mã hóa UTF- * theo định nghĩa có thể đại diện cho bất kỳ điểm mã Unicode nào hợp pháp để trao đổi. UCS-2 có thể đại diện ít hơn thế, cộng thêm một vài thứ nữa. Lặp lại: UCS-2 không phải là mã hóa Unicode hợp lệ, bất kỳ moreso nào hơn ASCII.
tchrist

1
"Tôi không hiểu ủng hộ việc sử dụng chung của Utf-8 . Nó được mã hóa theo chiều dài thay đổi (không thể truy cập bằng chỉ mục)"
Ian Boyd

9
@Ian Boyd, nhu cầu truy cập vào một ký tự riêng lẻ của một chuỗi trong một mẫu truy cập ngẫu nhiên là quá mức. Nó là phổ biến như muốn tính đường chéo của một ma trận các ký tự, đó là siêu hiếm. Các chuỗi hầu như luôn được xử lý tuần tự và vì việc truy cập UTF-8 char N + 1 cho rằng bạn đang ở UTF-8 char N là O (1), không có vấn đề gì. Có rất ít nhu cầu để thực hiện truy cập ngẫu nhiên của chuỗi. Cho dù bạn nghĩ rằng nó có giá trị không gian lưu trữ để đi đến UTF-32 thay vì UTF-8 là ý kiến ​​của riêng bạn, nhưng đối với tôi, nó hoàn toàn không phải là vấn đề.
tchrist

2
@tchrist, tôi sẽ cấp cho bạn các chuỗi hầu như luôn được xử lý tuần tự nếu bạn bao gồm phép lặp ngược là "tuần tự" và kéo dài thêm một chút so sánh đầu cuối của chuỗi với chuỗi đã biết. Hai kịch bản rất phổ biến là cắt ngắn khoảng trắng từ cuối chuỗi và kiểm tra phần mở rộng tệp ở cuối đường dẫn.
Andy Dent

11

Thêm phần này vào danh sách:

Kịch bản được trình bày rất đơn giản (thậm chí đơn giản hơn vì tôi sẽ trình bày ở đây so với ban đầu!): 1.A WinForms TextBox nằm trên một Biểu mẫu, trống rỗng. Nó có MaxLpm được đặt thành 20 .

2. Người dùng nhập vào TextBox hoặc có thể dán văn bản vào đó.

3. Không có vấn đề gì khi bạn nhập hoặc dán vào TextBox, bạn bị giới hạn ở mức 20, mặc dù vậy nó sẽ phát ra tiếng bíp ở văn bản ngoài 20 (YMMV ở đây; tôi đã thay đổi sơ đồ âm thanh của mình để mang lại cho tôi hiệu ứng đó!).

4. Gói văn bản nhỏ sau đó được gửi đi nơi khác, để bắt đầu một cuộc phiêu lưu thú vị.

Bây giờ đây là một kịch bản dễ dàng, và bất cứ ai cũng có thể viết nó lên, trong thời gian rảnh rỗi. Tôi chỉ tự viết nó bằng nhiều ngôn ngữ lập trình bằng WinForms, vì tôi đã chán và chưa bao giờ thử nó trước đây. Và với văn bản bằng nhiều ngôn ngữ thực tế bởi vì tôi có dây theo cách đó và có nhiều bố cục bàn phím hơn bất kỳ ai trong toàn bộ vũ trụ kỳ dị.

Tôi thậm chí còn đặt tên cho hình thức Magic Thảm Ride , để giúp cải thiện sự nhàm chán.

Điều này đã không làm việc, cho những gì nó có giá trị.

Vì vậy, thay vào đó, tôi đã nhập 20 ký tự sau vào mẫu Magic Ride Ride của mình :

0123401234012340123

À ồ.

Ký tự cuối cùng đó là U + 20000, ký tự mở rộng B đầu tiên của Unicode (còn gọi là U + d840 U + dc00, với những người bạn thân của anh ta, người mà anh ta không xấu hổ khi bị loại bỏ, như trước đây) ....

nhập mô tả hình ảnh ở đây

Và bây giờ chúng tôi có một trò chơi bóng.

Bởi vì khi TextBox.MaxLpm nói về

Nhận hoặc đặt số lượng ký tự tối đa có thể được nhập thủ công vào hộp văn bản.

những gì nó thực sự có nghĩa là

Nhận hoặc đặt số lượng tối đa các đơn vị mã UTF-16 LE có thể được nhập thủ công vào hộp văn bản và sẽ cắt xén một cách không thương tiếc ra khỏi bất kỳ chuỗi nào cố gắng chơi các trò chơi dễ thương với khái niệm ngôn ngữ mà chỉ có ai đó bị ám ảnh như rằng đồng bào Kaplan sẽ thấy khó chịu (anh ta cần phải ra ngoài nhiều hơn!).

Tôi sẽ thử và xem về việc cập nhật tài liệu ....
Những độc giả thường xuyên nhớ sê-ri UCS-2 đến UTF-16 của tôi sẽ ghi nhận sự không vui của tôi với khái niệm đơn giản về TextBox.MaxLpm và cách xử lý tối thiểu trong trường hợp này trong đó hành vi hà khắc của nó tạo ra một chuỗi bất hợp pháp, một phần mà các phần khác của .Net Framework có thể tạo ra một

  • System.Text.EncoderFallbackException: Không thể dịch ký tự Unicode \ uD850 tại chỉ mục 0 sang trang mã được chỉ định. *

ngoại lệ nếu bạn chuyển chuỗi này ở nơi khác trong .Net Framework (như đồng nghiệp của tôi Dan Thompson đang làm).

Bây giờ không sao, có lẽ loạt UCS-2 đến UTF-16 đầy đủ nằm ngoài tầm với của nhiều người.
Nhưng không hợp lý khi hy vọng rằng TextBox.Text sẽ không tạo ra System.Stringđiều đó sẽ không khiến một phần khác của .Net Framework bị ném? Ý tôi là, không có khả năng dưới dạng một sự kiện nào đó trên điều khiển cho bạn biết về việc cắt ngắn sắp tới nơi bạn có thể dễ dàng thêm xác thực thông minh hơn - xác thực mà chính điều khiển không bận tâm thực hiện. Tôi sẽ đi xa hơn để nói rằng sự kiểm soát punk này đang phá vỡ hợp đồng an toàn thậm chí có thể dẫn đến các vấn đề bảo mật nếu bạn có thể tạo ra các ngoại lệ không mong muốn để chấm dứt ứng dụng như một loại từ chối dịch vụ thô thiển. Tại sao bất kỳ quá trình hoặc phương pháp hoặc thuật toán hoặc kỹ thuật WinForms nào cũng tạo ra kết quả không hợp lệ?

Nguồn: Blog của Michael S. Kaplan MSDN


Cảm ơn, liên kết rất tốt! Tôi đã thêm nó vào danh sách các vấn đề trong câu hỏi.

9

Tôi không nhất thiết phải nói rằng UTF-16 có hại. Nó không thanh lịch, nhưng nó phục vụ mục đích tương thích ngược với UCS-2, giống như GB18030 làm với GB2312 và UTF-8 làm với ASCII.

Nhưng thực hiện một thay đổi cơ bản đối với cấu trúc Unicode ở giữa dòng, sau khi Microsoft và Sun đã xây dựng các API khổng lồ xung quanh các ký tự 16 bit, là có hại. Việc không truyền bá nhận thức về sự thay đổi có hại hơn .


8
UTF-8 là siêu bộ của ASCII, nhưng UTF-16 KHÔNG phải là siêu bộ của UCS-2. Mặc dù gần như là một superset, một mã hóa chính xác của UCS-2 thành UTF-8 dẫn đến sự gớm ghiếc được gọi là CESU-8; UCS-2 không có người thay thế, chỉ là các điểm mã thông thường, vì vậy chúng phải được dịch như vậy. Ưu điểm thực sự của UTF-16 là việc nâng cấp một cơ sở mã UCS-2 dễ dàng hơn so với việc viết lại hoàn toàn cho UTF-8. Buồn cười hả?

1
Chắc chắn, về mặt kỹ thuật UTF-16 không phải là siêu thay thế của UCS-2, nhưng khi nào thì U + D800 thành U + DFFF đã từng được sử dụng cho bất cứ điều gì ngoại trừ thay thế UTF-16?
dan04

2
Không quan trọng. Bất kỳ quá trình xử lý nào khác ngoài việc mù quáng đi qua bytestream đều yêu cầu bạn giải mã các cặp thay thế, điều mà bạn không thể làm nếu bạn coi nó là UCS-2.

6

UTF-16 là sự thỏa hiệp tốt nhất giữa xử lý và không gian và đó là lý do tại sao hầu hết các nền tảng chính (Win32, Java, .NET) sử dụng nó để biểu diễn bên trong chuỗi.


31
-1 vì UTF-8 có thể nhỏ hơn hoặc không khác biệt đáng kể. Đối với một số tập lệnh châu Á nhất định, UTF-8 là ba byte cho mỗi glyph trong khi UTF-16 chỉ có hai, nhưng điều này được cân bằng bởi UTF-8 chỉ là một byte cho ASCII (thường xuất hiện ngay cả trong các ngôn ngữ châu Á trong tên sản phẩm, lệnh và như vậy nhiều thứ). Hơn nữa, trong các ngôn ngữ đã nói, một glyph truyền tải nhiều thông tin hơn một ký tự Latin nên nó hợp lý để nó chiếm nhiều không gian hơn.

32
Tôi sẽ không gọi việc kết hợp các mặt xấu nhất của cả hai lựa chọn là một sự thỏa hiệp tốt.

18
Nó không dễ hơn UTF-8. Nó cũng có chiều dài thay đổi.
luiscubal

36
Bỏ các cuộc tranh luận về lợi ích của UTF-16 sang một bên: Những gì bạn đã trích dẫn không phải là lý do cho Windows, Java hoặc .NET sử dụng UTF-16. Windows và Java có từ thời Unicode là mã hóa 16 bit. UCS-2 là một lựa chọn hợp lý hồi đó. Khi Unicode trở thành mã hóa 21 bit di chuyển sang UTF-16 là nền tảng lựa chọn tốt nhất hiện có. Điều đó không có gì để làm với sự dễ dàng xử lý hoặc thỏa hiệp không gian. Đó chỉ là vấn đề di sản.
Joey

10
.NET kế thừa di sản Windows ở đây.
Joey

6

Tôi chưa bao giờ hiểu quan điểm của UTF-16. Nếu bạn muốn đại diện hiệu quả nhất về không gian, hãy sử dụng UTF-8. Nếu bạn muốn có thể coi văn bản là độ dài cố định, hãy sử dụng UTF-32. Nếu bạn không muốn, hãy sử dụng UTF-16. Tệ hơn nữa, vì tất cả các ký tự phổ biến (mặt phẳng đa ngôn ngữ cơ bản) trong UTF-16 đều khớp với một điểm mã duy nhất, các lỗi cho rằng UTF-16 có độ dài cố định sẽ khó tìm và khó tìm, trong khi đó nếu bạn cố gắng thực hiện Điều này với UTF-8, mã của bạn sẽ thất bại nhanh và lớn ngay khi bạn cố gắng quốc tế hóa.


6

Vì tôi chưa thể bình luận, tôi đăng bài này như một câu trả lời, vì dường như tôi không thể liên lạc với các tác giả utf8everywhere.org. Thật xấu hổ khi tôi không tự động nhận được đặc quyền bình luận, vì tôi có đủ danh tiếng trên các stackexchanges khác.

Điều này có nghĩa như là một nhận xét cho Ý kiến: Có, UTF-16 nên được coi là câu trả lời có hại .

Một chút điều chỉnh:

Để ngăn chặn việc vô tình đi qua một UTF-8 char*vào phiên bản ANSI-chuỗi các chức năng Windows API, ta nên xác định UNICODE, không _UNICODE. _UNICODEchức năng bản đồ như _tcslenđể wcslen, không MessageBoxđể MessageBoxW. Thay vào đó, UNICODEđịnh nghĩa sẽ chăm sóc cái sau. Để chứng minh, đây là từ WinUser.htiêu đề của MS Visual Studio 2005 :

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

Ở mức tối thiểu, lỗi này cần được sửa utf8everywhere.org.

Lời đề nghị:

Có lẽ hướng dẫn nên chứa một ví dụ về việc sử dụng rõ ràng phiên bản Chuỗi rộng của cấu trúc dữ liệu, để làm cho nó dễ dàng bỏ lỡ / quên nó. Việc sử dụng các phiên bản chuỗi cấu trúc dữ liệu trên đầu sử dụng các phiên bản chức năng của chuỗi rộng khiến cho người ta vô tình gọi một phiên bản chuỗi ANSI của chức năng đó.

Ví dụ về ví dụ:

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
if (hSearch != INVALID_HANDLE_VALUE)
{
    FindClose(hSearch);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
}

Đã đồng ý; cảm ơn! Chúng tôi sẽ cập nhật tài liệu. Tài liệu vẫn cần phát triển hơn và thêm thông tin về cơ sở dữ liệu. Chúng tôi rất vui khi nhận được sự đóng góp của các từ.
Pavel Radzivilovsky

@PavelRadzivilovsky _UNICODEvẫn còn đó :(
cubuspl42

cảm ơn vì đã nhắc nhở. cubus, Jelle, bạn có muốn một người dùng cho SVN của chúng tôi không?
Pavel Radzivilovsky

@Pavel Chắc chắn, sẽ đánh giá cao nó!
Jelle Geerts

@JelleGeerts: Tôi xin lỗi vì sự chậm trễ này. Bạn luôn có thể liên hệ với chúng tôi bằng email của chúng tôi (được liên kết từ bản tuyên ngôn) hoặc Facebook. Chúng tôi rất dễ tìm thấy. Mặc dù tôi tin rằng chúng tôi đã khắc phục sự cố mà bạn đã mang đến đây (và tôi đã ghi có cho bạn ở đó), toàn bộ các cuộc tranh luận UTF-8 so với UTF-16 vẫn có liên quan. Nếu bạn có nhiều đóng góp, hãy liên hệ với chúng tôi thông qua các kênh riêng tư đó.
ybungalobill

5

Có người nói UCS4 và UTF-32 giống nhau. Không như vậy, nhưng tôi biết ý của bạn. Một trong số đó là một mã hóa của người khác, mặc dù. Tôi ước họ đã nghĩ đến việc xác định sự tồn tại ngay từ đầu để chúng ta sẽ không có trận chiến cuối cùng ở đây. Họ không thể thấy điều đó sẽ đến sao? Ít nhất UTF-8 giống nhau ở mọi nơi (trừ khi có ai đó đang theo dõi thông số ban đầu với 6 byte).

Nếu bạn sử dụng UTF-16, bạn phải bao gồm việc xử lý các ký tự đa bào. Bạn không thể chuyển đến ký tự thứ N bằng cách lập chỉ mục 2N thành một mảng byte. Bạn phải đi bộ, hoặc có chỉ số nhân vật. Nếu không, bạn đã viết một lỗi.

Thông số dự thảo hiện tại của C ++ nói rằng UTF-32 và UTF-16 có thể có các biến thể nhỏ về cuối, cuối lớn và không xác định. Có thật không? Nếu Unicode đã chỉ định rằng tất cả mọi người phải làm endian nhỏ ngay từ đầu thì tất cả sẽ đơn giản hơn. (Tôi cũng sẽ ổn với người lớn cuối cùng.) Thay vào đó, một số người đã thực hiện nó theo cách này, cách khác, và bây giờ chúng tôi bị mắc kẹt với sự điên cuồng không vì điều gì. Đôi khi thật xấu hổ khi trở thành một kỹ sư phần mềm.


Endianess không xác định được cho là bao gồm BOM là ký tự đầu tiên, được sử dụng để xác định cách đọc chuỗi. UCS-4 và UTF-32 thực sự giống nhau ngày nay, tức là giá trị UCS số trong khoảng từ 0 đến 0x10FFFF được lưu trữ trong một số nguyên 32 bit.

5
@Tronic: Về mặt kỹ thuật, điều này không đúng. Mặc dù UCS-4 có thể lưu trữ bất kỳ số nguyên 32 bit nào, UTF-32 bị cấm lưu trữ các điểm mã không có ký tự không hợp lệ để trao đổi, chẳng hạn như 0xFFFF, 0xFFFE và tất cả các đại diện thay thế. UTF là một mã hóa vận chuyển, không phải là mã hóa nội bộ.
tchrist

Các vấn đề về endianness là không thể tránh khỏi miễn là các bộ xử lý khác nhau tiếp tục sử dụng các lệnh byte khác nhau. Tuy nhiên, nó có thể tốt nếu có thứ tự byte "ưa thích" để lưu trữ tệp UTF-16.
Qwertie

Mặc dù UTF-32 có chiều rộng cố định cho các điểm mã , nhưng nó không phải là chiều rộng cố định cho các ký tự . (Nghe nói về một cái gì đó gọi là "kết hợp các ký tự"?) Vì vậy, bạn không thể chuyển đến ký tự thứ N chỉ bằng cách lập chỉ mục 4N vào mảng byte.
musiphil

2

Tôi không nghĩ nó có hại nếu nhà phát triển đủ cẩn thận.
Và họ nên chấp nhận đánh đổi này nếu họ cũng biết rõ.

Là một nhà phát triển phần mềm Nhật Bản, tôi thấy UCS-2 đủ lớn và giới hạn không gian rõ ràng đơn giản hóa logic và giảm bộ nhớ thời gian chạy, vì vậy sử dụng utf-16 trong giới hạn UCS-2 là đủ tốt.

Có hệ thống tập tin hoặc ứng dụng khác giả định các điểm mã và byte theo tỷ lệ, do đó số lượng điểm mã thô có thể được đảm bảo phù hợp với một số lưu trữ kích thước cố định.

Một ví dụ là NTFS và VFAT chỉ định UCS-2 là mã hóa lưu trữ tên tệp của họ.

Nếu những ví dụ đó thực sự muốn mở rộng để hỗ trợ UCS-4, tôi có thể đồng ý sử dụng utf-8 cho mọi thứ, nhưng độ dài cố định có những điểm tốt như:

  1. có thể đảm bảo kích thước theo chiều dài (kích thước dữ liệu và độ dài mã hóa tỷ lệ thuận)
  2. có thể sử dụng số mã hóa để tra cứu băm
  3. dữ liệu không nén có kích thước hợp lý (so với utf-32 / UCS-4)

Trong tương lai khi sức mạnh bộ nhớ / xử lý rẻ ngay cả trong bất kỳ thiết bị nhúng nào, chúng tôi có thể chấp nhận thiết bị bị chậm một chút do lỗi bộ nhớ cache thêm hoặc lỗi trang và sử dụng bộ nhớ thêm, nhưng điều này sẽ không xảy ra trong tương lai gần ...


3
Đối với những người đọc nhận xét này, đáng chú ý rằng UCS-2 không giống với UTF-16. Hãy tìm kiếm sự khác biệt để hiểu.
mikebabcock

1

"Một trong những mã hóa phổ biến nhất, UTF-16, có nên được coi là có hại không?"

Rất có thể, nhưng các lựa chọn thay thế không nhất thiết phải được xem là tốt hơn nhiều.

Vấn đề cơ bản là có nhiều khái niệm khác nhau về: glyphs, ký tự, điểm mã và chuỗi byte. Ánh xạ giữa mỗi cái này là không tầm thường, ngay cả với sự trợ giúp của một thư viện chuẩn hóa. (Ví dụ: một số ký tự trong các ngôn ngữ châu Âu được viết bằng chữ viết gốc Latinh không được viết bằng một bảng mã Unicode duy nhất. khó khăn; lỗi kỳ lạ sẽ được dự kiến ​​(và thay vì chỉ than vãn về chúng ở đây, hãy nói với những người bảo trì phần mềm liên quan).

Cách duy nhất mà UTF-16 có thể được coi là có hại trái ngược với UTF-8 là nó có một cách mã hóa điểm khác bên ngoài BMP (như một cặp thay thế). Nếu mã muốn truy cập hoặc lặp theo điểm mã, điều đó có nghĩa là nó cần phải nhận thức được sự khác biệt. OTOH, điều đó có nghĩa là một khối lượng đáng kể mã hiện có giả định "ký tự" luôn có thể phù hợp với số lượng hai byte - một giả định khá phổ biến, nếu sai, ít nhất có thể tiếp tục hoạt động mà không cần xây dựng lại tất cả. Nói cách khác, ít nhất bạn có thể thấy những nhân vật không được xử lý đúng!

Tôi đặt câu hỏi của bạn lên đầu và nói rằng toàn bộ shebang chết tiệt của Unicode nên được coi là có hại và mọi người nên sử dụng mã hóa 8 bit, ngoại trừ tôi đã thấy (trong 20 năm qua) dẫn đến điều đó: thật kinh khủng nhầm lẫn về các bảng mã ISO 8859 khác nhau, cộng với toàn bộ các bộ được sử dụng cho Cyrillic và bộ EBCDIC, và tốt, Unicode cho tất cả các lỗi của nó. Giá như đó không phải là một sự thỏa hiệp khó chịu giữa những hiểu lầm của các quốc gia khác nhau.


Biết được may mắn của mình, trong một vài năm, chúng ta sẽ thấy mình hết chỗ trong UTF-16. Meh.
Donal Fellows

3
Vấn đề cơ bản là văn bản khó kiểm soát. Không có cách tiếp cận nào để thể hiện thông tin đó theo cách kỹ thuật số có thể không phức tạp. Đó là lý do tương tự mà ngày tháng khó khăn, lịch vất vả, thời gian khó khăn, tên cá nhân khó khăn, địa chỉ bưu chính khó khăn: bất cứ khi nào máy kỹ thuật số giao nhau với các cấu trúc văn hóa của con người, sự phức tạp nổ ra. Đó là một thực tế của cuộc sống. Con người không hoạt động trên logic kỹ thuật số.
Aristotle Pagaltzis
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.