Haruskah UTF-16 dianggap berbahaya?

432

Saya akan bertanya apa yang mungkin merupakan pertanyaan yang cukup kontroversial: "Haruskah salah satu pengkodean paling populer, UTF-16, dianggap berbahaya?"

Mengapa saya menanyakan pertanyaan ini?

Berapa banyak programmer yang menyadari fakta bahwa UTF-16 sebenarnya adalah penyandian panjang variabel? Maksud saya, ada poin kode yang, diwakili sebagai pasangan pengganti, mengambil lebih dari satu elemen.

Aku tahu; banyak aplikasi, kerangka kerja dan API menggunakan UTF-16, seperti Java's String, C #'s String, Win32 APIs, pustaka Qt GUI, pustaka ICU Unicode, dll. Namun, dengan semua itu, ada banyak bug dasar dalam pemrosesan karakter keluar dari BMP (karakter yang harus dikodekan menggunakan dua elemen UTF-16).

Misalnya, coba edit salah satu karakter ini:

Anda mungkin kehilangan beberapa, tergantung pada font apa yang telah Anda instal. Semua karakter ini berada di luar BMP (Basic Multilingual Plane). Jika Anda tidak dapat melihat karakter ini, Anda juga dapat mencoba melihatnya di referensi Karakter Unicode .

Misalnya, coba buat nama file di Windows yang menyertakan karakter ini; coba hapus karakter-karakter ini dengan "backspace" untuk melihat bagaimana mereka berperilaku dalam aplikasi yang berbeda yang menggunakan UTF-16. Saya melakukan beberapa tes dan hasilnya sangat buruk:

  • Opera bermasalah dengan pengeditannya (perlu hapus 2 penekanan pada backspace)
  • Notepad tidak dapat mengatasinya dengan benar (perlu hapus 2 penekanan pada backspace)
  • Pengeditan nama file dalam dialog Window in broken (perlu hapus 2 penekanan pada backspace)
  • Semua aplikasi QT3 tidak dapat mengatasinya - tampilkan dua kotak kosong bukan satu simbol.
  • Python menyandikan karakter seperti itu secara salah ketika digunakan secara langsung u'X'!=unicode('X','utf-16')pada beberapa platform ketika X dalam karakter di luar BMP.
  • Python 2.5 unicodedata gagal mendapatkan properti pada karakter seperti itu ketika python dikompilasi dengan string Unicode UTF-16.
  • StackOverflow tampaknya menghapus karakter ini dari teks jika diedit langsung sebagai karakter Unicode (karakter ini ditampilkan menggunakan HTML Unicode escapes).
  • WinForms TextBox dapat menghasilkan string yang tidak valid ketika dibatasi dengan MaxLength.

Tampaknya bug seperti itu sangat mudah ditemukan di banyak aplikasi yang menggunakan UTF-16.

Jadi ... Apakah Anda berpikir bahwa UTF-16 harus dianggap berbahaya?

Artyom
sumber
64
Tidak sepenuhnya benar. Saya jelaskan, jika Anda menulis "שָׁ" karakter majemuk yang terdiri dari "ש", "ָ" dan "ׁ", vovel, maka penghapusan masing-masingnya adalah logis, Anda menghapus satu titik kode ketika Anda menekan " backspace "dan hapus semua karakter termasuk vovel ketika menekan" del ". Tapi, Anda tidak pernah menghasilkan ilegal keadaan text - poin kode ilegal. Dengan demikian, situasi ketika Anda menekan backspace dan mendapatkan teks ilegal adalah salah.
41
CiscoIPPhone: Jika bug "dilaporkan beberapa kali berbeda, oleh banyak orang yang berbeda", dan kemudian beberapa tahun kemudian seorang pengembang menulis di blog dev bahwa "Percaya atau tidak, perilaku itu sebagian besar disengaja!", Lalu (untuk menempatkan itu agak) Saya cenderung berpikir itu mungkin bukan keputusan desain terbaik yang pernah dibuat. :-) Hanya karena disengaja bukan berarti itu bukan bug.
145
Pos yang bagus. UTF-16 memang yang "terburuk dari kedua dunia": UTF8 adalah variabel-panjang, mencakup semua Unicode, membutuhkan algoritma transformasi ke dan dari codepoint mentah, membatasi ke ASCII, dan tidak memiliki masalah endianness. UTF32 adalah fixed-length, tidak memerlukan transformasi, tetapi membutuhkan lebih banyak ruang dan memiliki masalah endianness. Sejauh ini bagus, Anda dapat menggunakan UTF32 secara internal dan UTF8 untuk serialisasi. Tetapi UTF16 tidak memiliki manfaat: Ini tergantung pada endian, panjang variabel, butuh banyak ruang, tidak kompatibel dengan ASCII. Upaya yang diperlukan untuk menangani UTF16 dengan benar dapat digunakan dengan lebih baik untuk UTF8.
Kerrek SB
26
@Ian: UTF-8 TIDAK memiliki peringatan yang sama dengan UTF-8. Anda tidak dapat memiliki pengganti di UTF-8. UTF-8 tidak menyamar sebagai sesuatu yang tidak, tetapi kebanyakan programmer menggunakan UTF-16 salah menggunakannya. Aku tahu. Saya telah memperhatikan mereka lagi dan lagi dan lagi dan lagi.
tchrist
18
Selain itu, UTF-8 tidak memiliki masalah karena semua orang memperlakukannya sebagai pengodean lebar variabel. Alasan UTF-16 memiliki masalah adalah karena semua orang memperlakukannya seperti pengkodean lebar tetap.
Christoffer Hammarström

Jawaban:

340

Ini jawaban lama.
Lihat UTF-8 Everywhere untuk pembaruan terbaru.

Opini: Ya, UTF-16 harus dianggap berbahaya . Alasan mengapa hal itu ada adalah karena beberapa waktu lalu dulu ada kepercayaan sesat bahwa widechar akan menjadi seperti apa UCS-4 sekarang.

Meskipun "anglo-sentralisme" dari UTF-8, itu harus dianggap sebagai satu-satunya penyandian teks yang bermanfaat. Orang dapat berargumen bahwa kode sumber program, halaman web dan file XML, nama file OS dan antarmuka teks komputer-ke-komputer lainnya seharusnya tidak pernah ada. Tetapi ketika mereka melakukannya, teks tidak hanya untuk pembaca manusia.

Di sisi lain, overhead UTF-8 adalah harga yang murah untuk dibayar sementara itu memiliki keuntungan yang signifikan. Keuntungan seperti kompatibilitas dengan kode tidak disadari yang baru saja melewati string char*. Ini adalah sesuatu yang bagus. Ada beberapa karakter berguna yang SHORTER di UTF-16 daripada di UTF-8.

Saya percaya bahwa semua pengkodean lainnya akan mati pada akhirnya. Ini melibatkan bahwa MS-Windows, Java, ICU, python berhenti menggunakannya sebagai favorit mereka. Setelah penelitian dan diskusi yang panjang, konvensi pengembangan di perusahaan saya melarang menggunakan UTF-16 di mana pun kecuali panggilan OS API, dan ini terlepas dari pentingnya kinerja dalam aplikasi kami dan fakta bahwa kami menggunakan Windows. Fungsi konversi dikembangkan untuk mengonversi UTF8 yang selalu diasumsikan std::stringmenjadi UTF-16 asli, yang Windows sendiri tidak mendukung dengan benar .

Untuk orang-orang yang mengatakan " gunakan apa yang dibutuhkan di tempat yang dibutuhkan ", saya katakan: ada keuntungan besar untuk menggunakan pengkodean yang sama di mana-mana, dan saya tidak melihat alasan yang cukup untuk melakukan sebaliknya. Secara khusus, saya pikir menambahkan wchar_tke C ++ adalah kesalahan, dan begitu pula penambahan Unicode ke C ++ 0x. Apa yang harus diminta dari implementasi STL adalah bahwa setiap std::stringatau char*parameter akan dianggap kompatibel dengan unicode.

Saya juga menentang pendekatan " gunakan apa yang Anda inginkan ". Saya tidak melihat alasan untuk kebebasan seperti itu. Ada cukup banyak kebingungan pada masalah teks, sehingga semua perangkat lunak yang rusak ini. Setelah mengatakan di atas, saya yakin bahwa programmer akhirnya harus mencapai konsensus tentang UTF-8 sebagai satu cara yang tepat. (Saya berasal dari negara yang tidak menggunakan bahasa Ascii dan dibesarkan di Windows, jadi saya yang terakhir diharapkan menyerang UTF-16 berdasarkan alasan agama).

Saya ingin berbagi informasi lebih lanjut tentang cara saya melakukan teks pada Windows, dan apa yang saya rekomendasikan kepada semua orang untuk diperiksa waktu kompilasi unicode, kemudahan penggunaan dan multi-platformness kode yang lebih baik. Saran ini sangat berbeda dari apa yang biasanya direkomendasikan sebagai cara yang tepat untuk menggunakan Unicode di windows. Namun, penelitian mendalam dari rekomendasi ini menghasilkan kesimpulan yang sama. Jadi begini:

  • Jangan gunakan wchar_tatau std::wstringdi tempat lain selain titik yang berdekatan dengan API yang menerima UTF-16.
  • Jangan gunakan _T("")atau L""UTF-16 literal (Ini harus IMO dikeluarkan dari standar, sebagai bagian dari penghentian UTF-16).
  • Jangan gunakan jenis, fungsi atau turunannya yang sensitif terhadap _UNICODEkonstanta, seperti LPTSTRatau CreateWindow().
  • Namun, _UNICODEselalu didefinisikan, untuk menghindari memberikan char*string ke WinAPI dikompilasi secara diam-diam
  • std::stringsdan char*di mana saja dalam program dianggap UTF-8 (jika tidak dikatakan sebaliknya)
  • Semua string saya std::string, meskipun Anda dapat meneruskan char * atau string literal ke convert(const std::string &).
  • hanya menggunakan fungsi Win32 yang menerima widechars ( LPWSTR). Tidak pernah mereka yang menerima LPTSTRatau LPSTR. Lewati parameter dengan cara ini:

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

    (Kebijakan tersebut menggunakan fungsi konversi di bawah.)

  • Dengan string 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);
    
  • Bekerja dengan file, nama file, dan aliran pada Windows:

    • Jangan pernah memberikan std::stringatau const char*mengajukan argumen nama kepada fstreamkeluarga. MSVC STL tidak mendukung argumen UTF-8, tetapi memiliki ekstensi non-standar yang harus digunakan sebagai berikut:
    • Konversi std::stringargumen menjadi std::wstringdengan Utils::Convert:

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

      Kita harus menghapus konversi secara manual, ketika sikap MSVC fstreamberubah.

    • Kode ini bukan multi-platform dan mungkin harus diubah secara manual di masa mendatang
    • Lihat fstreamkasus / penelitian 4215 unicode untuk informasi lebih lanjut.
    • Jangan pernah menghasilkan file output teks dengan konten non-UTF8
    • Hindari penggunaan fopen()karena alasan RAII / OOD. Jika perlu, gunakan _wfopen()dan WinAPI konvensi di atas.

// 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
}
Pavel Radzivilovsky
sumber
39
Saya tidak bisa setuju. Keuntungan utf16 daripada utf8 untuk banyak bahasa Asia sepenuhnya mendominasi poin yang Anda buat. Adalah naif untuk berharap bahwa orang Jepang, Thailand, Cina, dll. Akan melepaskan pengkodean ini. Bentrokan bermasalah antara rangkaian karakter adalah ketika rangkaian karakter sebagian besar tampak serupa, kecuali dengan perbedaan. Saya menyarankan standardisasi pada: fixed 7bit: iso-irv-170; Variabel 8bit: utf8; Variabel 16bit: utf16; 32bit diperbaiki: ucs4.
82
@ Charles: terima kasih atas masukan Anda. Benar, beberapa karakter BMP lebih panjang di UTF-8 daripada di UTF-16. Tapi, mari kita hadapi itu: masalahnya bukan dalam byte yang diambil karakter Cina BMP, tetapi kompleksitas desain perangkat lunak yang muncul. Jika seorang programmer Cina harus mendesain untuk karakter panjang variabel, sepertinya UTF-8 masih merupakan harga kecil untuk dibayar dibandingkan dengan variabel lain dalam sistem. Dia mungkin menggunakan UTF-16 sebagai algoritma kompresi jika ruang sangat penting, tetapi itupun tidak cocok untuk LZ, dan setelah LZ atau kompresi generik lainnya keduanya membutuhkan ukuran dan entropi yang sama.
32
Apa yang saya katakan pada dasarnya adalah bahwa penyederhanaan ditawarkan dengan memiliki One encoding yang juga kompatibel dengan program char * yang ada, dan juga yang paling populer saat ini untuk semuanya tidak terbayangkan. Ini hampir seperti di hari-hari "plaintext" yang baik. Ingin membuka file dengan nama? Tidak perlu peduli apa jenis unicode yang Anda lakukan, dll. Saya sarankan kita, pengembang, membatasi UTF-16 ke kasus yang sangat khusus dari optimasi parah di mana sedikit kinerja bernilai pekerjaan man-bulan.
17
Linux memiliki persyaratan khusus ketika memilih untuk menggunakan UTF-8 secara internal: kompatibilitas dengan Unix. Windows tidak membutuhkan itu, dan dengan demikian ketika pengembang mengimplementasikan Unicode, mereka menambahkan versi UCS-2 dari hampir semua fungsi yang menangani teks dan membuat multibyte yang hanya dikonversi ke UCS-2 dan memanggil yang lain. Mereka kemudian menggantikan UCS-2 dengan UTF-16. Linux di sisi lain tetap melakukan penyandian 8-bit dan dengan demikian menggunakan UTF-8, karena itu adalah pilihan yang tepat dalam kasus itu.
Mircea Chirea
34
@Pavel Radzivilovsky: BTW, tulisan Anda tentang "Saya percaya bahwa semua penyandian lain pada akhirnya akan mati. Ini melibatkan MS-Windows, Java, ICU, python berhenti menggunakannya sebagai favorit mereka." dan "Secara khusus, saya pikir menambahkan wchar_t ke C ++ adalah kesalahan, dan begitu juga penambahan unicode ke C ++ Ox." entah sangat naif atau sangat sombong. Dan ini datang dari seseorang yang mengkode di rumah dengan Linux dan yang senang dengan karakter UTF-8. Terus terang: Itu tidak akan terjadi .
paercebal
157

Codepoints unicode bukan karakter! Kadang-kadang mereka bahkan bukan mesin terbang (bentuk visual).

Beberapa contoh:

  • Codepoint angka romawi seperti "ⅲ". (Karakter tunggal yang terlihat seperti "iii".)
  • Karakter beraksen seperti "á", yang dapat direpresentasikan sebagai karakter gabungan tunggal "\ u00e1" atau karakter dan diakritik terpisah "\ u0061 \ u0301".
  • Karakter seperti sigma huruf kecil Yunani, yang memiliki bentuk berbeda untuk posisi kata tengah ("σ") dan akhir ("ς"), tetapi yang harus dianggap sinonim untuk pencarian.
  • Unicode discretionary hyphen U + 00AD, yang mungkin atau mungkin tidak ditampilkan secara visual, tergantung pada konteksnya, dan yang diabaikan untuk pencarian semantik.

Satu-satunya cara untuk mendapatkan pengeditan Unicode yang benar adalah dengan menggunakan perpustakaan yang ditulis oleh seorang ahli , atau menjadi seorang ahli dan menulis sendiri. Jika Anda hanya menghitung codepoint, Anda hidup dalam keadaan dosa.

Daniel Newby
sumber
19
Ini. Sangat banyak ini. UTF-16 dapat menyebabkan masalah, tetapi bahkan menggunakan UTF-32 sepanjang dapat (dan akan) masih memberi Anda masalah.
bcat
11
Apa itu karakter? Anda dapat mendefinisikan titik kode sebagai karakter dan mendapatkan cukup banyak dengan baik. Jika Anda maksudkan mesin terbang yang terlihat pengguna, itu sesuatu yang lain.
tchrist
7
@tchrist yakin untuk mengalokasikan ruang definisi itu baik-baik saja, tetapi untuk hal lain? Tidak terlalu banyak. Jika Anda menangani karakter kombinasi sebagai satu-satunya karakter (yaitu untuk operasi hapus atau "ambil karakter pertama") Anda akan mendapatkan perilaku aneh dan salah. Jika suatu titik kode hanya memiliki makna ketika dikombinasikan dengan setidaknya yang lain, Anda tidak dapat mengatasinya sendiri dengan cara yang masuk akal.
Voo
6
@ Peracerier, ini terlambat ke pesta, tapi saya harus mengomentari itu. Beberapa bahasa memiliki kumpulan kombinasi potensial diakritik yang sangat besar (lihat Vietnam, mis. Mệt đ.). Memiliki kombinasi daripada satu karakter per diakritik sangat membantu.
asthasr
21
catatan kecil terminologi: codepoints jangan sesuai dengan karakter unicode ; apa yang Daniel bicarakan di sini adalah karakter yang dirasakan pengguna , yang sesuai dengan cluster graphic unicode
Christoph
54

Ada aturan sederhana tentang apa yang Unicode Transformation Form (UTF) gunakan: - utf-8 untuk penyimpanan dan komunikasi - utf-16 untuk pemrosesan data - Anda bisa menggunakan utf-32 jika sebagian besar platform API yang Anda gunakan adalah utf-32 (umum di dunia UNIX).

Sebagian besar sistem saat ini menggunakan utf-16 (Windows, Mac OS, Java, .NET, ICU, Qt). Lihat juga dokumen ini: http://unicode.org/notes/tn12/

Kembali ke "UTF-16 sebagai berbahaya", saya akan mengatakan: pasti tidak.

Orang-orang yang takut akan pengganti (berpikir bahwa mereka mengubah Unicode menjadi pengkodean variabel-panjang) tidak memahami kompleksitas (cara yang lebih besar) lainnya yang membuat pemetaan antara karakter dan titik kode Unicode sangat kompleks: menggabungkan karakter, pengikat, pemilih pemilih , mengontrol karakter, dll.

Baca seri ini di sini http://www.siao2.com/2009/06/29/9800913.aspx dan lihat bagaimana UTF-16 menjadi masalah yang mudah.

Mihai Nita
sumber
26
Silakan tambahkan beberapa contoh di mana UTF-32 adalah umum di dunia UNIX!
maxschlepzig
48
Tidak, Anda tidak ingin menggunakan UTF-16 untuk pemrosesan data. Ini menyebalkan. Ini memiliki semua kelemahan UTF-8 tetapi tidak ada kelebihannya. Baik UTF-8 dan UTF-32 jelas lebih unggul dari peretas yang sebelumnya dikenal sebagai Nyonya UTF-16, yang nama gadisnya adalah UCS-2.
tchrist
34
Saya kemarin baru saja menemukan bug dalam metode Java inti String kelas equalsIgnoreCase(juga yang lain di kelas string) yang tidak akan pernah ada jika Java digunakan baik UTF-8 atau UTF-32. Ada jutaan bom tidur dalam kode apa pun yang menggunakan UTF-16, dan saya muak dan bosan dengan itu. UTF-16 adalah cacar ganas yang mengganggu perangkat lunak kami dengan bug berbahaya selamanya. Ini jelas berbahaya, dan harus ditinggalkan dan dilarang.
tchrist
7
@tchrist Wow jadi fungsi sadar non-pengganti (karena itu ditulis ketika tidak ada dan sayangnya didokumentasikan sedemikian rupa sehingga mungkin tidak mungkin untuk beradaptasi - itu menentukan .toUpperCase (char)) akan mengakibatkan perilaku yang salah? Anda sadar bahwa fungsi UTF-32 dengan peta titik kode usang tidak akan menangani ini lebih baik? Juga seluruh Java API menangani pengganti tidak terlalu baik dan poin yang lebih rumit tentang Unicode tidak sama sekali - dan dengan kemudian pengkodean yang digunakan tidak masalah sama sekali.
Voo
8
-1: Sebuah tanpa syarat .Substring(1)dalam .NET adalah contoh sepele dari sesuatu yang memecah dukungan untuk semua Unicode non-BMP. Segala sesuatu yang menggunakan UTF-16 memiliki masalah ini; terlalu mudah untuk memperlakukannya sebagai pengodean dengan lebar tetap, dan Anda melihat masalah terlalu jarang. Itu membuatnya menjadi pengkodean yang aktif berbahaya jika Anda ingin mendukung Unicode.
Roman Starkov
43

Ya, tentu saja.

Mengapa? Itu ada hubungannya dengan menggunakan kode .

Jika Anda melihat statistik penggunaan codepoint ini pada sebuah corpus besar oleh Tom Christiansen, Anda akan melihat bahwa codepoint BMP trans-8bit digunakan beberapa pesanan jika besarnya lebih dari pada codepoint non-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

Ambil diktum TDD: "Kode yang belum diuji adalah kode yang rusak", dan ulangi kata itu sebagai "kode yang tidak dieksekusi adalah kode yang rusak", dan pikirkan seberapa sering programmer harus berurusan dengan titik-titik kode non-BMP.

Bug yang terkait dengan tidak berurusan dengan UTF-16 sebagai pengodean lebar variabel lebih mungkin tidak diketahui daripada bug yang setara di UTF-8 . Beberapa bahasa pemrograman masih tidak menjamin untuk memberi Anda UTF-16, bukan UCS-2, dan beberapa bahasa pemrograman tingkat tinggi menawarkan akses ke unit kode alih-alih kode-poin (bahkan C seharusnya memberi Anda akses ke codepoints jika Anda gunakan wchar_t, terlepas dari apa yang mungkin dilakukan beberapa platform).

ninjalj
sumber
16
"Bug yang terkait dengan tidak berurusan dengan UTF-16 sebagai pengodean lebar variabel lebih mungkin tidak diketahui daripada bug yang setara di UTF-8." Inilah inti masalah, dan karenanya, jawaban yang benar.
Sean McMillan
3
Tepat. Jika penanganan UTF-8 Anda borked, itu akan segera jelas. Jika penanganan UTF-8 Anda borked, Anda hanya akan melihat jika Anda memasukkan karakter Han atau simbol matematika yang tidak biasa.
Siput mekanik
1
Sangat benar, tetapi di sisi lain, untuk apa unit test jika Anda harus bergantung pada keberuntungan untuk menemukan bug pada kasus yang lebih jarang?
musiphil
@musiphil: jadi, kapan terakhir kali Anda membuat unit test untuk karakter non-BMP?
ninjalj
1
Untuk menguraikan pernyataan saya sebelumnya: bahkan dengan UTF-8, Anda tidak dapat yakin bahwa Anda telah membahas semua kasus setelah hanya melihat beberapa contoh yang berfungsi. Sama dengan UTF-16: Anda perlu menguji apakah kode Anda berfungsi baik dengan non-pengganti maupun dengan pengganti. (Seseorang bahkan dapat berargumentasi bahwa UTF-8 memiliki setidaknya empat kasus utama sementara UTF-16 hanya memiliki dua.)
musiphil
40

Saya akan menyarankan bahwa berpikir UTF-16 mungkin dianggap berbahaya mengatakan bahwa Anda perlu mendapatkan pemahaman yang lebih besar tentang unicode .

Karena saya telah kalah memilih untuk menyampaikan pendapat saya tentang pertanyaan subyektif, izinkan saya menguraikan. Apa sebenarnya yang mengganggu Anda tentang UTF-16? Apakah Anda lebih suka jika semuanya dikodekan dalam UTF-8? UTF-7? Atau bagaimana dengan UCS-4? Tentu saja aplikasi tertentu tidak dirancang untuk menangani kode karakter setiap orang di luar sana - tetapi mereka diperlukan, terutama dalam domain informasi global saat ini, untuk komunikasi antar batas internasional.

Tapi sungguh, jika Anda merasa UTF-16 harus dianggap berbahaya karena membingungkan atau dapat diimplementasikan secara tidak benar (unicode tentu saja bisa), lalu metode pengkodean karakter apa yang dianggap tidak berbahaya?

EDIT: Untuk memperjelas: Mengapa menganggap implementasi yang tidak tepat dari suatu standar mencerminkan kualitas dari standar itu sendiri? Seperti yang telah dicatat oleh orang lain, hanya karena aplikasi menggunakan alat secara tidak tepat, tidak berarti bahwa alat itu sendiri rusak. Jika itu masalahnya, kita mungkin bisa mengatakan hal-hal seperti "kata kunci var dianggap berbahaya", atau "threading dianggap berbahaya". Saya pikir pertanyaannya membingungkan kualitas dan sifat standar dengan kesulitan yang dimiliki banyak programmer dalam menerapkan dan menggunakannya dengan benar, yang saya rasa lebih berasal dari kurangnya pemahaman mereka tentang bagaimana unicode bekerja, daripada unicode itu sendiri.

patjb
sumber
33
-1: Bagaimana kalau menangani beberapa keberatan Artyom, daripada hanya menggurui dia?
8
BTW: Ketika saya mulai menulis artikel ini saya hampir ingin menulis "Apakah artikel Joel on Softeare dari Unicode harus dianggap berbahaya" karena ada banyak kesalahan. Sebagai contoh: pengkodean utf-8 membutuhkan hingga 4 karakter dan bukan 6. Juga tidak membedakan antara UCS-2 dan UTF-16 yang benar-benar berbeda - dan benar-benar menyebabkan masalah yang saya bicarakan.
32
Juga, perlu dicatat bahwa ketika Joel menulis artikel itu, standar UTF-8 WS 6 byte, bukan 4. RFC 3629 mengubah standar menjadi 4 byte beberapa bulan SETELAH dia menulis artikel. Seperti kebanyakan hal lain di internet, Anda harus membaca lebih dari satu sumber, dan mengetahui usia sumber Anda. Tautan itu tidak dimaksudkan sebagai "akhir semua menjadi semua", tetapi lebih sebagai titik awal.
7
Saya akan pic: utf-8 atau utf-32 yaitu: penyandian panjang variabel di hampir semua kasus (termasuk BMP) atau penyandian panjang tetap selalu.
18
@iconiK: Jangan konyol. UTF-16 sama sekali bukan standar de facto untuk memproses teks. Perlihatkan saya bahasa pemrograman yang lebih cocok untuk pemrosesan teks yang Perl, yang selalu (lebih dari satu dekade) menggunakan karakter abstrak dengan representasi UTF-8 yang mendasarinya secara internal. Karena itu, setiap program Perl secara otomatis menangani semua Unicode tanpa pengguna harus terus-menerus berkeliling dengan pengganti yang idiot. Panjang string dihitung dalam poin kode, bukan unit kode. Hal lain adalah kebodohan belaka yang menempatkan kompatibilitas mundur ke belakang.
tchrist
37

Tidak ada yang salah dengan pengkodean Utf-16. Tetapi bahasa yang memperlakukan unit 16-bit sebagai karakter mungkin harus dianggap dirancang dengan buruk. Memiliki tipe bernama ' char' yang tidak selalu mewakili karakter cukup membingungkan. Karena sebagian besar pengembang akan mengharapkan tipe char untuk mewakili titik kode atau karakter, banyak kode mungkin akan rusak ketika terkena karakter di luar BMP.

Perhatikan bahwa meskipun menggunakan utf-32 tidak berarti bahwa setiap titik kode 32-bit akan selalu mewakili karakter. Karena menggabungkan karakter, karakter yang sebenarnya dapat terdiri dari beberapa titik kode. Unicode tidak pernah sepele.

BTW. Mungkin ada kelas bug yang sama dengan platform dan aplikasi yang mengharapkan karakter menjadi 8-bit, yang diberi makan Utf-8.

JacquesB
sumber
12
Dalam kasus Java, jika Anda melihat timeline mereka ( java.com/en/javahistory/timeline.jsp ), Anda melihat bahwa pengembangan utama String terjadi ketika Unicode 16 bit (diubah pada tahun 1996). Mereka harus meningkatkan kemampuan untuk menangani poin kode non BMP, sehingga kebingungan.
Kathy Van Stone
10
@ Kathy: Tapi sebenarnya bukan alasan untuk C #. Secara umum, saya setuju, bahwa harus ada CodePointtipe, memegang satu titik kode (21 bit), CodeUnittipe, memegang unit kode tunggal (16 bit untuk UTF-16) dan suatu Charactertipe idealnya harus mendukung grapheme lengkap. Tapi itu membuatnya secara fungsional setara dengan String...
Joey
1
Jawaban ini sudah hampir dua tahun, tetapi saya tidak bisa tidak mengomentarinya. "Memiliki tipe bernama 'char' yang tidak selalu mewakili karakter cukup membingungkan." Namun orang-orang menggunakannya sepanjang waktu dalam C dan sejenisnya untuk mewakili data integer yang dapat disimpan dalam satu byte.
JAB
Dan saya telah melihat banyak kode C yang tidak menangani pengkodean karakter dengan benar.
dan04
1
C # memiliki alasan yang berbeda: itu dirancang untuk Windows, dan Windows dibangun di atas UCS-2 (sangat menjengkelkan bahwa bahkan hari ini API Windows tidak dapat mendukung UTF-8). Plus, saya pikir Microsoft menginginkan kompatibilitas Java (.NET 1.0 memiliki perpustakaan kompatibilitas Java, tetapi mereka menjatuhkan dukungan Java dengan sangat cepat - saya kira ini disebabkan gugatan Sun terhadap MS?)
Qwertie
20

Pilihan pribadi saya adalah selalu menggunakan UTF-8. Ini standar di Linux untuk hampir semuanya. Ini kompatibel dengan banyak aplikasi lawas. Ada overhead yang sangat minimal dalam hal ruang ekstra yang digunakan untuk karakter non-latin vs format UTF lainnya, dan ada penghematan yang signifikan dalam ruang untuk karakter latin. Di web, bahasa latin berkuasa, dan saya pikir mereka akan melakukannya di masa mendatang. Dan untuk mengatasi salah satu argumen utama dalam posting asli: hampir setiap programmer menyadari bahwa terkadang UTF-8 memiliki karakter multi-byte di dalamnya. Tidak semua orang berurusan dengan ini dengan benar, tetapi mereka biasanya sadar, yang lebih dari yang bisa dikatakan untuk UTF-16. Tapi, tentu saja, Anda harus memilih yang paling sesuai untuk aplikasi Anda. Itu sebabnya ada lebih dari satu.

rmeador
sumber
3
UTF-16 lebih sederhana untuk apa pun di dalam BMP, itu sebabnya ia digunakan secara luas. Tapi saya penggemar UTF-8 juga, tidak ada masalah dengan urutan byte, yang berfungsi untuk keuntungannya.
Malcolm
2
Secara teoritis, ya. Dalam prakteknya ada hal-hal seperti, katakanlah, UTF-16BE, yang berarti UTF-16 dalam big endian tanpa BOM. Ini bukan sesuatu yang saya buat, ini adalah pengkodean yang sebenarnya diizinkan dalam ID3v2.4 tag (ID3v2 tag menghisap, tetapi sayangnya digunakan secara luas). Dan dalam kasus seperti itu Anda harus mendefinisikan endianness secara eksternal, karena teks itu sendiri tidak mengandung BOM. UTF-8 selalu ditulis satu arah dan tidak ada masalah.
Malcolm
23
Tidak, UTF-16 tidak sederhana. Itu lebih sulit. Ini menyesatkan dan menipu Anda untuk berpikir itu lebar tetap. Semua kode tersebut rusak dan semua lebih karena Anda tidak melihat sampai terlambat. CASE IN POINT: Saya baru saja menemukan bug UTF-16 bodoh lain di perpustakaan inti Java kemarin, kali ini di String.equalsIgnoreCase, yang tersisa di buggery braindeath UCS-2, dan gagal pada 16/17 poin kode Unicode yang valid. Berapa lama kode itu ada? Tidak ada alasan untuk itu menjadi buggy. UTF-16 mengarah pada kebodohan belaka dan kecelakaan menunggu untuk terjadi. Jalankan berteriak dari UTF-16.
tchrist
3
@tchrist One harus menjadi pengembang yang sangat bodoh untuk tidak tahu bahwa UTF-16 tidak panjang tetap. Jika Anda mulai dengan Wikipedia, Anda akan membaca yang berikut di bagian paling atas: "Ini menghasilkan hasil panjang variabel dari satu atau dua unit kode 16-bit per titik kode". FAQ Unicode mengatakan hal yang sama: unicode.org/faq//utf_bom.html#utf16-1 . Saya tidak tahu, bagaimana UTF-16 dapat menipu siapa pun jika ditulis di mana-mana yang panjangnya bervariasi. Adapun metode, itu tidak pernah dirancang untuk UTF-16 dan tidak boleh dianggap Unicode, sesederhana itu.
Malcolm
2
@tchrist Apakah Anda memiliki sumber untuk statistik Anda? Meskipun jika programmer yang baik langka, saya pikir ini bagus, karena kita menjadi lebih berharga. :) Sedangkan untuk Java API, bagian berbasis char pada akhirnya mungkin akan ditinggalkan, tetapi ini bukan jaminan bahwa mereka tidak akan digunakan. Dan mereka pasti tidak akan dihapus karena alasan kompatibilitas.
Malcolm
18

Ya, ada pengkodean yang menggunakan simbol ukuran tetap. Maksud saya UTF-32. Tetapi 4 byte untuk setiap simbol terlalu banyak ruang terbuang, mengapa kita menggunakannya dalam situasi sehari-hari?

Menurut saya, sebagian besar masalah muncul dari kenyataan bahwa beberapa perangkat lunak berada di belakang standar Unicode, tetapi tidak cepat untuk memperbaiki situasi. Opera, Windows, Python, Qt - semuanya muncul sebelum UTF-16 dikenal luas atau bahkan muncul. Namun, saya dapat mengonfirmasi bahwa di Opera, Windows Explorer, dan Notepad tidak ada masalah dengan karakter di luar BMP lagi (setidaknya pada PC saya). Tapi bagaimanapun, jika program tidak mengenali pasangan pengganti, maka mereka tidak menggunakan UTF-16. Apa pun masalah yang timbul dari berurusan dengan program-program tersebut, mereka tidak ada hubungannya dengan UTF-16 itu sendiri.

Namun, saya berpikir bahwa masalah perangkat lunak lama dengan hanya dukungan BMP agak berlebihan. Karakter di luar BMP hanya ditemui dalam kasus dan wilayah yang sangat spesifik. Menurut FAQ resmi Unicode , "bahkan dalam teks Asia Timur, kejadian pasangan pengganti harus rata-rata kurang dari 1% dari semua penyimpanan teks rata-rata". Tentu saja, karakter di luar BMP tidak boleh diabaikan karena program tidak sesuai dengan Unicode, tetapi sebagian besar program tidak dimaksudkan untuk bekerja dengan teks yang mengandung karakter tersebut. Itu sebabnya jika mereka tidak mendukungnya, itu tidak menyenangkan, tetapi bukan bencana.

Sekarang mari kita pertimbangkan alternatifnya. Jika UTF-16 tidak ada, maka kami tidak akan memiliki pengkodean yang cocok untuk teks non-ASCII, dan semua perangkat lunak yang dibuat untuk UCS-2 harus sepenuhnya dirancang ulang untuk tetap sesuai dengan Unicode. Yang terakhir kemungkinan besar hanya akan memperlambat adopsi Unicode. Kami juga tidak akan dapat mempertahankan kompabilitas dengan teks dalam UCS-2 seperti UTF-8 dalam kaitannya dengan ASCII.

Sekarang, dengan mengesampingkan semua masalah warisan, apa argumen yang menentang pengkodean itu sendiri? Saya benar-benar ragu bahwa pengembang saat ini tidak tahu bahwa UTF-16 panjang variabel, ditulis di mana-mana yang dimulai dengan Wikipedia. UTF-16 jauh lebih sulit diurai daripada UTF-8, jika seseorang menunjukkan kompleksitas sebagai masalah yang mungkin terjadi. Juga salah untuk berpikir bahwa mudah untuk mengacaukan dengan menentukan panjang string hanya di UTF-16. Jika Anda menggunakan UTF-8 atau UTF-32, Anda masih harus menyadari bahwa satu titik kode Unicode tidak selalu berarti satu karakter. Selain itu, saya tidak berpikir ada sesuatu yang substansial terhadap penyandian.

Karena itu saya tidak berpikir bahwa pengkodean itu sendiri harus dianggap berbahaya. UTF-16 adalah kompromi antara kesederhanaan dan kekompakan, dan tidak ada salahnya menggunakan apa yang diperlukan di mana itu diperlukan . Dalam beberapa kasus Anda harus tetap kompatibel dengan ASCII dan Anda perlu UTF-8, dalam beberapa kasus Anda ingin bekerja dengan bekerja dengan ideograf Han dan menghemat ruang menggunakan UTF-16, dalam beberapa kasus Anda perlu representasi universal karakter menggunakan tanda tetap pengkodean panjang. Gunakan apa yang lebih tepat, lakukan saja dengan benar.

Malcolm
sumber
21
Pandangan Anglo-sentris yang agak berkedip, Malcolm. Hampir setara dengan "ASCII cukup baik untuk AS - seluruh dunia harus cocok dengan kita".
Jonathan Leffler
28
Sebenarnya saya dari Rusia dan bertemu cyrillics sepanjang waktu (termasuk program saya sendiri), jadi saya tidak berpikir bahwa saya memiliki pandangan Anglo-sentris. :) Menyebutkan ASCII tidak tepat, karena itu bukan Unicode dan tidak mendukung karakter tertentu. UTF-8, UTF-16, UTF-32 mendukung rangkaian karakter internasional yang sama, mereka hanya dimaksudkan untuk digunakan dalam bidang spesifik mereka. Dan inilah tepatnya poin saya: jika Anda menggunakan sebagian besar bahasa Inggris, gunakan UTF-8, jika Anda kebanyakan menggunakan cyrillics, gunakan UTF-16, jika Anda menggunakan bahasa kuno, gunakan UTF-32. Cukup sederhana.
Malcolm
16
"Tidak benar, skrip Asia seperti Jepang, Cina atau Arab juga milik BMP. BMP itu sendiri sebenarnya sangat besar dan tentu saja cukup besar untuk memasukkan semua skrip yang digunakan saat ini" Ini semua sangat salah. BMP berisi 0xFFFF karakter (65536). Cina sendiri memiliki lebih dari itu. Standar Cina (GB 18030) memiliki lebih dari itu. Unicode 5.1 sudah mengalokasikan lebih dari 100.000 karakter.
12
@Marcolm: "BMP itu sendiri sebenarnya sangat besar dan tentu saja cukup besar untuk memasukkan semua skrip yang digunakan saat ini" Tidak benar. Pada titik ini Unicode sudah mengalokasikan sekitar 100 ribu karakter, jauh lebih banyak daripada yang dapat diakomodasi oleh BMP. Ada potongan besar karakter Cina di luar BMP. Dan beberapa di antaranya diwajibkan oleh GB-18030 (standar Cina wajib). Lainnya diharuskan oleh standar (tidak wajib) Jepang dan Korea. Jadi, jika Anda mencoba menjual apa pun di pasar-pasar itu, Anda perlu di luar dukungan BMP.
8
Apa pun yang menggunakan UTF-16 tetapi hanya dapat menangani karakter BMP sempit sebenarnya tidak menggunakan UTF-16. Itu buggy dan rusak. Premis OP adalah suara: UTF-16 berbahaya, karena itu membuat orang naif menulis kode yang rusak. Entah Anda dapat menangani teks Unicode, atau Anda tidak bisa. Jika Anda tidak bisa, maka Anda memilih subset, yang sama bodohnya dengan pemrosesan teks ASCII saja.
tchrist
16

Bertahun-tahun Windows internasionalisasi bekerja terutama dalam bahasa-bahasa Asia Timur mungkin telah merusak saya, tetapi saya condong ke UTF-16 untuk representasi string internal-ke-program, dan UTF-8 untuk penyimpanan jaringan atau file dokumen seperti plaintext. UTF-16 biasanya dapat diproses lebih cepat di Windows, jadi itulah manfaat utama menggunakan UTF-16 di Windows.

Membuat lompatan ke UTF-16 secara dramatis meningkatkan kecukupan produk rata-rata yang menangani teks internasional. Hanya ada beberapa kasus sempit ketika pasangan pengganti perlu dipertimbangkan (penghapusan, penyisipan, dan pemecahan garis, pada dasarnya) dan sebagian besar kasing rata-rata adalah pass-through langsung. Dan tidak seperti pengkodean sebelumnya seperti varian JIS, UTF-16 membatasi pasangan pengganti untuk rentang yang sangat sempit, sehingga pemeriksaannya sangat cepat dan bekerja maju dan mundur.

Memang, ini kira-kira sama cepatnya dengan UTF-8 yang dikodekan dengan benar. Tetapi ada juga banyak aplikasi UTF-8 yang rusak yang secara salah mengkodekan pasangan pengganti sebagai dua urutan UTF-8. Jadi UTF-8 tidak menjamin keselamatan juga.

IE menangani pasangan pengganti dengan cukup baik sejak 2000 atau lebih, meskipun biasanya mengubah mereka dari halaman UTF-8 ke representasi UTF-16 internal; Saya cukup yakin Firefox telah melakukannya dengan benar juga, jadi saya tidak begitu peduli apa yang dilakukan Opera.

UTF-32 (alias UCS4) tidak ada gunanya untuk sebagian besar aplikasi karena ini sangat menuntut ruang, jadi ini cukup nonstarter.

Jason True
sumber
6
Saya tidak mendapatkan komentar Anda tentang UTF-8 dan pasangan pengganti. Pasangan pengganti hanya konsep yang bermakna dalam pengkodean UTF-16, bukan? Mungkin kode yang mengkonversi langsung dari pengkodean UTF-16 ke pengkodean UTF-8 mungkin salah, dan dalam hal ini, masalahnya adalah membaca UTF-16 yang salah, bukan menulis UTF-8. Apakah itu benar?
Craig McQueen
11
Apa yang Jason bicarakan adalah perangkat lunak yang dengan sengaja mengimplementasikan UTF-8 seperti itu: membuat pasangan pengganti, lalu UTF-8 mengkodekan setiap bagian secara terpisah. Nama yang benar untuk pengkodean itu adalah CESU-8, tetapi Oracle (mis) salah mengartikannya sebagai UTF-8. Java menggunakan skema yang sama untuk serialisasi objek, tetapi jelas didokumentasikan sebagai "Modified UTF-8" dan hanya untuk penggunaan internal. (Sekarang, jika kita bisa membuat orang untuk MEMBACA dokumentasi itu dan berhenti menggunakan DataInputStream # readUTF () dan DataOutputStream # writeUTF () secara tidak tepat ...)
AFAIK, UTF-32 masih pengkodean variabel panjang, dan tidak sama dengan UCS4 yang merupakan kisaran spesifik dari titik kode.
Eonil
@Eonil, UTF-32 hanya akan dibedakan dari UCS4 jika kita memiliki standar Unicode yang menampilkan sesuatu seperti UCS5 atau lebih besar.
JasonTrue
@JasonTrue Namun, hanya hasilnya yang sama secara kebetulan, tidak dijamin oleh desain. Hal yang sama terjadi pada pengalamatan memori 32-bit, Y2K, UTF16 / UCS2. Atau apakah kita punya jaminan kesetaraan itu? Jika sudah, saya dengan senang hati akan menggunakannya. Tetapi saya tidak ingin menulis kemungkinan kode yang dapat pecah . Saya menulis kode tingkat karakter, dan tidak adanya cara yang dijamin untuk transkode antara UTF <-> titik kode banyak mengganggu saya.
Eonil
16

UTF-8 jelas merupakan cara yang harus ditempuh, mungkin disertai dengan UTF-32 untuk penggunaan internal dalam algoritma yang memerlukan akses acak berkinerja tinggi (tetapi mengabaikan kombinasi karakter).

Baik UTF-16 dan UTF-32 (serta varian LE / BE mereka) mengalami masalah endianess, sehingga mereka tidak boleh digunakan secara eksternal.

Tronic
sumber
9
Akses acak waktu konstan juga dimungkinkan dengan UTF-8, cukup gunakan unit kode daripada titik kode. Mungkin Anda memerlukan akses titik kode acak nyata, tetapi saya belum pernah melihat kasus penggunaan, dan Anda cenderung menginginkan akses cluster grapheme acak sebagai gantinya.
15

UTF-16? pasti berbahaya. Hanya sebutir garam saya di sini, tetapi ada tiga penyandian teks yang dapat diterima dalam sebuah program:

  • ASCII: ketika berhadapan dengan hal-hal tingkat rendah (misalnya: mikrokontroler) yang tidak mampu membeli yang lebih baik
  • UTF8: penyimpanan dalam media dengan lebar tetap seperti file
  • integer codepoints ("CP"?): array bilangan bulat terbesar yang nyaman untuk bahasa dan platform pemrograman Anda (meluruh ke ASCII dalam batas resorpsi rendah). Seharusnya int32 pada komputer lama dan int64 pada apa pun dengan pengalamatan 64-bit.

  • Jelas antarmuka ke kode lama menggunakan pengkodean apa yang diperlukan untuk membuat kode lama berfungsi dengan benar.

David X
sumber
4
@simon buchan, U+10ffffmax akan keluar jendela ketika (tidak jika) mereka kehabisan codepoints. Yang mengatakan, menggunakan int32 pada sistem p64 untuk kecepatan mungkin aman, karena saya ragu mereka akan melebihi U+ffffffffsebelum Anda dipaksa untuk menulis ulang kode Anda untuk sistem 128 bit sekitar 2050. (Itulah titik "gunakan int terbesar yang nyaman "sebagai kebalikan dari" terbesar yang tersedia "(yang mungkin int256 atau bignum atau sesuatu).)
David X
1
@ David: Unicode 5.2 mengkodekan 107.361 codepoint. Ada 867.169 codepoint yang tidak digunakan. "Kapan" itu konyol. Codepoint Unicode didefinisikan sebagai angka dari 0 hingga 0x10FFFF, properti yang bergantung pada UTF-16. (Juga tahun 2050 tampaknya jauh lebih rendah dari perkiraan untuk sistem 128 bit ketika sistem 64-bit dapat menampung keseluruhan Internet di ruang alamatnya.)
3
@ David: "Kapan" Anda mengacu pada kehabisan titik kode Unicode, bukan saklar 128-bit yang, ya, akan ada dalam beberapa abad mendatang. Tidak seperti memori, tidak ada pertumbuhan karakter yang eksponensial, sehingga Konsorsium Unicode secara khusus menjamin mereka tidak akan pernah mengalokasikan codepoint di atas U+10FFFF. Ini benar-benar adalah salah satu situasi ketika 21 bit sudah cukup untuk siapa pun.
10
@Simon Buchan: Setidaknya sampai kontak pertama. :)
3
Unicode digunakan untuk menjamin bahwa tidak akan ada poin kode di atas U + FFFF juga.
Shannon Severance
13

Unicode mendefinisikan poin kode hingga 0x10FFFF (1.114.112 kode), semua aplikasi yang berjalan di lingkungan multibahasa berurusan dengan string / nama file, dll. Harus menanganinya dengan benar.

Utf-16 : hanya mencakup 1.112.064 kode. Meskipun yang ada di akhir Unicode berasal dari pesawat 15-16 (Area Penggunaan Pribadi). Itu tidak dapat tumbuh lebih jauh di masa depan kecuali melanggar konsep Utf-16 .

Utf-8 : mencakup secara teoritis 2.216.757.376 kode. Rentang kode Unicode saat ini dapat diwakili oleh urutan maksimal 4 byte. Itu tidak menderita dengan masalah urutan byte , itu "kompatibel" dengan ascii.

Utf-32 : mencakup secara teoritis 2 ^ 32 = 4.294.967.296 kode. Saat ini tidak panjang variabel dikodekan dan mungkin tidak akan di masa depan.

Fakta-fakta itu jelas. Saya tidak mengerti menganjurkan penggunaan umum Utf-16 . Ini adalah variabel panjang yang disandikan (tidak dapat diakses oleh indeks), ia memiliki masalah untuk mencakup seluruh rentang Unicode bahkan saat ini, pesanan byte harus ditangani, dll. Saya tidak melihat keuntungan apa pun kecuali bahwa itu digunakan secara asli di Windows dan beberapa tempat lain. Meskipun saat menulis kode multi-platform, mungkin lebih baik menggunakan Utf-8 secara asli dan melakukan konversi hanya pada titik akhir dengan cara yang bergantung pada platform (seperti yang sudah disarankan). Ketika akses langsung dengan indeks diperlukan dan memori tidak menjadi masalah, Utf-32 harus digunakan.

Masalah utama adalah bahwa banyak programmer yang berurusan dengan Windows Unicode = Utf-16 bahkan tidak tahu atau mengabaikan fakta bahwa itu adalah panjang variabel yang dikodekan.

Cara biasanya di platform * nix cukup bagus, c string (char *) diartikan sebagai Utf-8 dikodekan, string c lebar (wchar_t *) diartikan sebagai Utf-32 .

Pavel Machyniak
sumber
7
Catatan: UTF-16 tidak mencakup Semua Unicode karena Unicode Consortium memutuskan bahwa 10FFFF adalah kisaran TOP Unicode dan didefinisikan UTF-8 maksimal 4 byte panjang dan secara eksplisit mengecualikan kisaran 0xD800-0xDFFF dari rentang titik kode yang valid dan rentang ini digunakan untuk pembuatan pasangan pengganti. Jadi setiap teks Unicode yang valid dapat direpresentasikan dengan masing-masing dari salah satu penyandian ini. Juga tentang tumbuh ke masa depan. Sepertinya 1 Juta poin kode tidak akan cukup di masa depan.
7
@ Gerrek: Salah: UCS-2 bukan pengkodean Unicode yang valid. Semua pengkodean UTF- * menurut definisi dapat mewakili titik kode Unicode apa pun yang sah untuk dipertukarkan. UCS-2 dapat mewakili jauh lebih sedikit dari itu, ditambah beberapa lagi. Ulangi: UCS-2 bukan pengkodean Unicode yang valid, lebih dari ASCII.
tchrist
1
"Saya tidak mengerti menganjurkan penggunaan umum Utf-8 . Ini adalah panjang variabel yang dikodekan (tidak dapat diakses oleh indeks)"
Ian Boyd
9
@Ian Boyd, kebutuhan untuk mengakses karakter individu string dalam pola akses acak sangat dilebih-lebihkan. Ini hampir sama dengan keinginan untuk menghitung diagonal dari sebuah matriks karakter, yang sangat langka. String hampir selalu diproses secara berurutan, dan karena mengakses UTF-8 char N +1 diberikan karena Anda berada di UTF-8 char N adalah O (1), tidak ada masalah. Ada sedikit kebutuhan untuk membuat akses acak string. Apakah menurut Anda layak ruang penyimpanan untuk pergi ke UTF-32 dan bukan UTF-8 adalah pendapat Anda sendiri, tetapi bagi saya, itu sama sekali bukan masalah.
tchrist
2
@tchrist, saya akan memberi Anda string hampir selalu diproses secara berurutan jika Anda memasukkan iterasi terbalik sebagai "berurutan" dan meregangkan sedikit perbandingan lebih lanjut dari ujung trailing string ke string yang dikenal. Dua skenario yang sangat umum adalah memotong spasi putih dari ujung string dan memeriksa ekstensi file di ujung jalan.
Andy Dent
11

Tambahkan ini ke daftar:

Skenario yang disajikan adalah sederhana (bahkan lebih sederhana karena saya akan menyajikannya di sini daripada pada awalnya!): 1.A WinForms TextBox duduk di Formulir, kosong. Ini memiliki MaxLength yang diatur ke 20 .

2.Pengguna mengetik ke dalam TextBox, atau mungkin menempelkan teks ke dalamnya.

3.Tidak peduli apa yang Anda ketik atau tempel ke dalam TextBox, Anda terbatas pada 20, meskipun akan berbunyi bip secara simpatik pada teks di luar 20 (YMMV di sini; Saya mengubah skema suara saya untuk memberi saya efek itu!).

4. Paket teks kecil kemudian dikirim ke tempat lain, untuk memulai petualangan yang mengasyikkan.

Sekarang ini adalah skenario yang mudah, dan siapa pun dapat menulis ini, di waktu luang mereka. Saya hanya menulis sendiri dalam beberapa bahasa pemrograman menggunakan WinForms, karena saya bosan dan belum pernah mencobanya sebelumnya. Dan dengan teks dalam berbagai bahasa aktual karena saya terhubung dengan kabel dan memiliki lebih banyak tata letak keyboard daripada siapa pun di seluruh alam semesta yang panik.

Aku bahkan menamai formulir Magic Carpet Ride , untuk membantu memperbaiki kebosanan.

Ini tidak berhasil, untuk apa nilainya.

Jadi sebagai gantinya, saya memasukkan 20 karakter berikut ke dalam formulir Magic Carpet Ride saya :

0123401234012340123 𠀀

Uh oh.

Karakter terakhir itu adalah U + 20000, ideograf Extension B pertama dari Unicode (alias U + d840 U + dc00, kepada teman-teman dekatnya yang tidak malu disingkap, seolah-olah, di depan) ....

masukkan deskripsi gambar di sini

Dan sekarang kami memiliki permainan bola.

Karena ketika TextBox.MaxLength berbicara tentang

Mendapat atau menetapkan jumlah karakter maksimum yang dapat dimasukkan secara manual ke dalam kotak teks.

apa itu sebenarnya berarti

Mendapat atau menetapkan jumlah maksimum unit kode UTF-16 LE yang dapat dimasukkan secara manual ke dalam kotak teks dan akan tanpa ampun memotong omong kosong yang hidup dari string apa pun yang mencoba memainkan permainan imut dengan gagasan karakter linguistik bahwa hanya seseorang yang terobsesi dengan Kaplan itu akan merasa ofensif (Ya ampun dia perlu keluar lebih banyak!).

Saya akan mencoba dan melihat tentang mendapatkan dokumen yang diperbarui ....
Pembaca reguler yang mengingat seri UCS-2 sampai UTF-16 saya akan mencatat ketidakbahagiaan saya dengan gagasan sederhana tentang TextBox.MaxLength dan bagaimana penanganannya minimal dalam kasus ini. di mana perilaku kejamnya menciptakan urutan ilegal, salah satu yang melemparkan bagian lain dari .Net Framework a

  • System.Text.EncoderFallbackException: Tidak dapat menerjemahkan karakter Unicode \ uD850 pada indeks 0 ke halaman kode yang ditentukan. *

pengecualian jika Anda melewatkan string ini di tempat lain di .Net Framework (seperti yang dilakukan rekan saya Dan Thompson).

Sekarang oke, mungkin seri UCS-2 ke UTF-16 penuh berada di luar jangkauan banyak orang.
Tapi bukankah masuk akal untuk mengharapkan TextBox.Text tidak akan menghasilkan System.Stringyang tidak akan menyebabkan potongan lain dari .Net Framework untuk dibuang? Maksud saya, ini tidak seperti ada peluang dalam bentuk beberapa peristiwa pada kontrol yang memberi tahu Anda tentang pemotongan yang akan datang di mana Anda dapat dengan mudah menambahkan validasi yang lebih cerdas - validasi bahwa kontrol itu sendiri tidak keberatan dilakukan. Saya akan mengatakan bahwa kontrol punk ini melanggar kontrak keselamatan yang bahkan dapat menyebabkan masalah keamanan jika Anda dapat membuat pengecualian yang tidak terduga untuk menghentikan aplikasi sebagai semacam penolakan kasar terhadap layanan. Mengapa proses atau metode atau algoritma atau teknik WinForms apa pun menghasilkan hasil yang tidak valid?

Sumber: Michael S. Kaplan Blog MSDN

Matthieu
sumber
Terima kasih, tautannya sangat bagus! Saya telah menambahkannya ke daftar masalah di pertanyaan.
9

Saya tidak perlu mengatakan bahwa UTF-16 berbahaya. Itu tidak elegan, tetapi melayani tujuan kompatibilitas mundur dengan UCS-2, seperti halnya GB18030 dengan GB2312, dan UTF-8 tidak dengan ASCII.

Tetapi membuat perubahan mendasar pada struktur Unicode di tengah aliran, setelah Microsoft dan Sun membangun API besar sekitar karakter 16-bit, berbahaya. Kegagalan untuk menyebarkan kesadaran akan perubahan itu lebih berbahaya.

dan04
sumber
8
UTF-8 adalah superset dari ASCII, tetapi UTF-16 BUKAN superset dari UCS-2. Meskipun hampir superset, pengkodean yang benar dari UCS-2 ke dalam UTF-8 menghasilkan kekejian yang dikenal sebagai CESU-8; UCS-2 tidak memiliki pengganti, hanya titik kode biasa, sehingga harus diterjemahkan seperti itu. Keuntungan sebenarnya dari UTF-16 adalah lebih mudah untuk meningkatkan basis kode UCS-2 daripada penulisan ulang lengkap untuk UTF-8. Lucu ya?
1
Tentu, secara teknis UTF-16 bukanlah superset dari UCS-2, tetapi kapan U + D800 hingga U + DFFF pernah digunakan untuk apa pun kecuali pengganti UTF-16?
dan04
2
Tidak masalah. Pemrosesan apa pun selain secara buta melewati bytestream mengharuskan Anda untuk memecahkan kode pasangan pengganti, yang tidak dapat Anda lakukan jika Anda memperlakukannya sebagai UCS-2.
6

UTF-16 adalah kompromi terbaik antara penanganan dan ruang dan itulah mengapa sebagian besar platform utama (Win32, Java, .NET) menggunakannya untuk representasi internal string.

Nemanja Trifunovic
sumber
31
-1 karena UTF-8 cenderung lebih kecil atau tidak berbeda nyata. Untuk skrip Asia tertentu, UTF-8 adalah tiga byte per mesin terbang, sementara UTF-16 hanya dua, tetapi ini diseimbangkan oleh UTF-8 yang hanya satu byte untuk ASCII (yang sering muncul bahkan dalam bahasa asia dalam nama produk, perintah, dan sebagainya. sesuatu). Selanjutnya, dalam bahasa tersebut, mesin terbang menyampaikan lebih banyak informasi daripada karakter latin sehingga dibenarkan untuk mengambil lebih banyak ruang.
32
Saya tidak akan menyebut menggabungkan sisi terburuk dari kedua opsi itu kompromi yang baik.
18
Ini tidak lebih mudah daripada UTF-8. Itu panjang variabel juga.
luiscubal
36
Mengesampingkan perdebatan tentang manfaat UTF-16: Apa yang Anda kutip bukan alasan untuk Windows, Java atau .NET menggunakan UTF-16. Windows dan Java tanggal kembali ke waktu di mana Unicode adalah enkode 16-bit. UCS-2 adalah pilihan yang masuk akal saat itu. Ketika Unicode menjadi 21-bit encoding bermigrasi ke UTF-16 adalah platform terbaik pilihan yang ada. Itu tidak ada hubungannya dengan kemudahan penanganan atau kompromi ruang. Itu hanya masalah warisan.
Joey
10
.NET mewarisi warisan Windows di sini.
Joey
6

Saya tidak pernah mengerti maksud UTF-16. Jika Anda menginginkan representasi paling hemat ruang, gunakan UTF-8. Jika Anda ingin dapat memperlakukan teks sebagai panjang tetap, gunakan UTF-32. Jika Anda tidak menginginkan keduanya, gunakan UTF-16. Lebih buruk lagi, karena semua karakter umum (bidang multibahasa dasar) dalam UTF-16 muat dalam satu titik kode, bug yang menganggap bahwa UTF-16 adalah fixed-length akan sulit ditemukan, sedangkan jika Anda mencoba melakukan ini dengan UTF-8, kode Anda akan gagal dengan cepat dan keras segera setelah Anda mencoba menginternasionalkan.

dsimcha
sumber
6

Karena saya belum bisa berkomentar, saya memposting ini sebagai jawaban, karena sepertinya saya tidak bisa menghubungi penulis dari utf8everywhere.org. Sayang sekali saya tidak secara otomatis mendapatkan hak istimewa komentar, karena saya memiliki cukup reputasi di stackexchanges lainnya.

Ini dimaksudkan sebagai komentar pada Pendapat: Ya, UTF-16 harus dianggap sebagai jawaban yang berbahaya .

Satu koreksi kecil:

Untuk mencegah satu dari secara tidak sengaja melewatkan UTF-8 char*ke versi ANSI-string fungsi Windows-API, orang harus mendefinisikan UNICODE, bukan _UNICODE. _UNICODEfungsi peta seperti _tcslenuntuk wcslen, tidak MessageBoxuntuk MessageBoxW. Alih-alih, UNICODEdefinisi tersebut mengatur yang terakhir. Sebagai bukti, ini dari WinUser.hheader MS Visual Studio 2005 :

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

Paling tidak, kesalahan ini harus diperbaiki utf8everywhere.org.

Sebuah sugesti:

Mungkin panduan ini harus berisi contoh penggunaan eksplisit dari versi Lebar-string dari struktur data, untuk membuatnya lebih mudah ketinggalan / lupakan. Menggunakan versi Lebar-string dari struktur data di atas menggunakan versi Lebar-fungsi fungsi membuatnya lebih kecil kemungkinannya bahwa seseorang secara tidak sengaja memanggil versi ANSI-string dari fungsi semacam itu.

Contoh dari contoh:

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);
}
Jelle Geerts
sumber
Sepakat; Terima kasih! Kami akan memperbarui dokumen. Dokumen masih membutuhkan pengembangan lebih lanjut dan menambahkan informasi tentang database. Kami senang menerima kontribusi kata-kata.
Pavel Radzivilovsky
@PavelRadzivilovsky _UNICODEmasih ada di sana :(
cubuspl42
Terima kasih telah mengingatkan. cubus, Jelle, Apakah Anda ingin pengguna untuk SVN kami?
Pavel Radzivilovsky
@Pavel Tentu, sangat menghargainya!
Jelle Geerts
@JelleGeerts: Saya minta maaf atas keterlambatan ini. Anda selalu dapat menghubungi kami melalui email kami (ditautkan dari manifesto) atau Facebook. Kami mudah ditemukan. Meskipun saya yakin kami telah memperbaiki masalah yang Anda bawa ke sini (dan saya memberi Anda kredit di sana), seluruh perdebatan UTF-8 vs UTF-16 masih relevan. Jika Anda memiliki lebih banyak untuk berkontribusi, jangan ragu untuk menghubungi kami melalui saluran pribadi tersebut.
ybungalobill
5

Seseorang mengatakan UCS4 dan UTF-32 sama. Tidak, tapi saya tahu apa yang Anda maksud. Salah satunya adalah pengkodean yang lain. Saya berharap mereka berpikir untuk menentukan endianness dari yang pertama sehingga kita tidak akan memiliki pertempuran endianess yang diperjuangkan di sini juga. Tidak bisakah mereka melihat kedatangan itu? Setidaknya UTF-8 adalah sama di mana-mana (kecuali seseorang mengikuti spesifikasi asli dengan 6-byte).

Jika Anda menggunakan UTF-16 Anda harus memasukkan penanganan untuk karakter multibyte. Anda tidak dapat pergi ke karakter Nth dengan mengindeks 2N ke dalam array byte. Anda harus berjalan, atau memiliki indeks karakter. Kalau tidak, Anda sudah menulis bug.

Draf spesifikasi C ++ saat ini mengatakan bahwa UTF-32 dan UTF-16 dapat memiliki varian little-endian, big-endian, dan tidak spesifik. Benarkah? Jika Unicode telah menetapkan bahwa setiap orang harus melakukan little-endian dari awal maka semuanya akan lebih sederhana. (Saya akan baik-baik saja dengan big-endian juga.) Sebaliknya, beberapa orang menerapkannya satu cara, beberapa yang lain, dan sekarang kita terjebak dengan kekonyolan untuk apa-apa. Terkadang memalukan menjadi insinyur perangkat lunak.

pengguna22815
sumber
Endianess yang tidak ditentukan seharusnya memasukkan BOM sebagai karakter pertama, yang digunakan untuk menentukan ke arah mana string harus dibaca. UCS-4 dan UTF-32 memang sama saat ini, yaitu nilai UCS numerik antara 0 dan 0x10FFFF disimpan dalam integer 32 bit.
5
@Tronic: Secara teknis, ini tidak benar. Meskipun UCS-4 dapat menyimpan integer 32-bit, UTF-32 dilarang menyimpan titik kode non-karakter yang ilegal untuk dipertukarkan, seperti 0xFFFF, 0xFFFE, dan semua pengganti. UTF adalah pengkodean transportasi, bukan yang internal.
tchrist
Masalah endianness tidak dapat dihindari selama prosesor yang berbeda terus menggunakan perintah byte yang berbeda. Namun, mungkin lebih baik jika ada urutan byte "pilihan" untuk penyimpanan file UTF-16.
Qwertie
Meskipun UTF-32 adalah lebar tetap untuk titik kode , ini bukan lebar tetap untuk karakter . (Pernah mendengar sesuatu yang disebut "menggabungkan karakter"?) Jadi Anda tidak dapat pergi ke karakter N'th hanya dengan mengindeks 4N ke dalam array byte.
musiphil
2

Saya tidak berpikir itu berbahaya jika pengembang cukup hati-hati.
Dan mereka harus menerima pertukaran ini jika mereka tahu juga.

Sebagai pengembang perangkat lunak Jepang, saya menemukan UCS-2 cukup besar dan membatasi ruang tampaknya menyederhanakan logika dan mengurangi memori runtime, jadi menggunakan utf-16 di bawah batasan UCS-2 cukup baik.

Ada filesystem atau aplikasi lain yang menganggap codepoint dan byte proporsional, sehingga nomor codepoint mentah dapat dijamin sesuai dengan beberapa penyimpanan ukuran tetap.

Salah satu contoh adalah NTFS dan VFAT menentukan UCS-2 sebagai pengkodean penyimpanan nama file mereka.

Jika contoh tersebut benar-benar ingin diperluas untuk mendukung UCS-4, saya bisa setuju menggunakan utf-8 untuk semuanya, tetapi panjang tetap memiliki poin yang baik seperti:

  1. dapat menjamin ukuran berdasarkan panjang (ukuran data dan panjang codepoint sebanding)
  2. dapat menggunakan nomor penyandian untuk pencarian hash
  3. data yang tidak dikompresi berukuran cukup (dibandingkan dengan utf-32 / UCS-4)

Di masa depan ketika memori / kekuatan pemrosesan murah bahkan di perangkat embed, kami dapat menerima perangkat menjadi agak lambat untuk kesalahan cache tambahan atau kesalahan halaman dan penggunaan memori tambahan, tetapi ini tidak akan terjadi dalam waktu dekat saya kira ...

holmes
sumber
3
Bagi mereka yang membaca komentar ini, perlu dicatat bahwa UCS-2 tidak sama dengan UTF-16. Silakan lihat perbedaannya untuk mengerti.
mikebabcock
1

"Haruskah salah satu pengkodean paling populer, UTF-16, dianggap berbahaya?"

Sangat mungkin, tetapi alternatifnya tidak harus dipandang sebagai jauh lebih baik.

Masalah mendasar adalah bahwa ada banyak konsep berbeda tentang: mesin terbang, karakter, codepoint dan urutan byte. Pemetaan antara masing-masing adalah non-sepele, bahkan dengan bantuan perpustakaan normalisasi. (Sebagai contoh, beberapa karakter dalam bahasa Eropa yang ditulis dengan skrip berbasis Latin tidak ditulis dengan satu titik kode Unicode. Dan itu adalah akhir dari kerumitan yang lebih sederhana!) Apa artinya ini adalah untuk mendapatkan semuanya dengan benar sangat menakjubkan sulit; bug aneh diharapkan (dan bukannya hanya mengeluh tentang mereka di sini, beri tahu pengelola perangkat lunak yang bersangkutan).

Satu-satunya cara di mana UTF-16 dapat dianggap berbahaya sebagai kebalikan dari, katakanlah, UTF-8 adalah bahwa ia memiliki cara berbeda untuk menyandikan titik kode di luar BMP (sebagai pasangan pengganti). Jika kode ingin mengakses atau beralih berdasarkan titik kode, itu berarti perlu menyadari perbedaannya. OTOH, itu berarti bahwa tubuh substansial dari kode yang ada yang mengasumsikan "karakter" selalu dapat masuk ke dalam kuantitas dua byte - asumsi yang cukup umum, jika salah, - setidaknya dapat terus bekerja tanpa membangun kembali semuanya. Dengan kata lain, setidaknya Anda bisa melihat karakter yang tidak ditangani dengan benar!

Saya akan memutar pertanyaan Anda dan mengatakan bahwa seluruh shebang sialan Unicode harus dianggap berbahaya dan semua orang harus menggunakan pengkodean 8-bit, kecuali saya telah melihat (selama 20 tahun terakhir) di mana itu mengarah: mengerikan kebingungan atas berbagai pengkodean ISO 8859, ditambah seluruh rangkaian yang digunakan untuk Cyrillic, dan paket EBCDIC, dan ... yah, Unicode untuk semua kesalahannya mengalahkan itu. Kalau saja itu bukan kompromi jahat antara kesalahpahaman berbagai negara.

Donal Fellows
sumber
Mengetahui keberuntungan kita, dalam beberapa tahun kita akan kehabisan ruang di UTF-16. Ah.
Donal Fellows
3
Masalah mendasarnya adalah teks itu sangat sulit. Tidak ada pendekatan untuk menyatakan bahwa informasi dengan cara digital tidak rumit. Itu alasan yang sama bahwa kencan itu sulit, kalender itu sulit, waktu sulit, nama pribadi sulit, alamat pos sulit: kapan pun mesin digital berpotongan dengan konstruksi budaya manusia, kompleksitas meletus. Itu adalah fakta kehidupan. Manusia tidak berfungsi pada logika digital.
Aristoteles Pagaltzis