Apakah UTF-16 memiliki lebar tetap atau lebar variabel? Mengapa UTF-8 tidak memiliki masalah byte-order?

16
  1. Apakah UTF-16 memiliki lebar tetap atau lebar variabel? Saya mendapat hasil berbeda dari sumber berbeda:

    Dari http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :

    UTF-16 menyimpan karakter Unicode dalam potongan enam belas-bit.

    Dari http://en.wikipedia.org/wiki/UTF-16/UCS-2 :

    UTF-16 (16-bit Unicode Transformation Format) adalah pengkodean karakter untuk Unicode yang mampu mengkodekan angka 1.112.064 [1] (disebut titik kode) dalam ruang kode Unicode dari 0 hingga 0x10FFFF. Ini menghasilkan hasil panjang variabel dari satu atau dua unit kode 16-bit per titik kode.

  2. Dari sumber pertama

    UTF-8 juga memiliki keunggulan bahwa unit encoding adalah byte, sehingga tidak ada masalah pemesanan byte.

    Mengapa UTF-8 tidak memiliki masalah byte-order? Lebar variabel, dan satu karakter dapat berisi lebih dari satu byte, jadi saya pikir byte-order masih bisa menjadi masalah?

Terima kasih dan salam!

StackExchange untuk Semua
sumber
Artikel hebat ini, Yang Mutlak Minimum Setiap Pengembang Perangkat Lunak Yang Benar-Benar Positif Harus Tahu Tentang Unicode dan Set Karakter (Tanpa Alasan!) Akan membantu menjawab semua pertanyaan Anda tentang Unicode dan UTF ..
Sorceror

Jawaban:

13

(1) Apa yang dimaksud dengan urutan byte, sebuah array dari char di C? Apakah UTF-16 urutan byte, atau apakah itu? (2) Mengapa urutan byte tidak ada hubungannya dengan panjang variabel?

Anda tampaknya salah paham tentang masalah endian. Berikut ringkasan singkatnya.

Bilangan bulat 32-bit membutuhkan 4 byte. Sekarang, kita tahu urutan logis dari byte ini. Jika Anda memiliki integer 32-bit, Anda bisa mendapatkan byte tinggi ini dengan kode berikut:

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

Semuanya baik dan bagus. Di mana masalahnya dimulai adalah bagaimana berbagai perangkat keras menyimpan dan mengambil bilangan bulat dari memori.

Dalam urutan Big Endian, sepotong memori 4 byte yang Anda baca sebagai integer 32-bit akan dibaca dengan byte pertama menjadi byte tinggi:

[0][1][2][3]

Dalam urutan Little Endian, sepotong memori 4 byte yang Anda baca sebagai integer 32-bit akan dibaca dengan byte pertama menjadi byte rendah :

[3][2][1][0]

Jika Anda memiliki pointer ke pointer ke nilai 32-bit, Anda bisa melakukan ini:

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

Menurut C / C ++, hasil ini tidak terdefinisi. Itu bisa 0x81. Atau bisa juga 0x32. Secara teknis, itu bisa mengembalikan apa pun, tetapi untuk sistem nyata, itu akan mengembalikan satu atau yang lain.

Jika Anda memiliki pointer ke alamat memori, Anda dapat membaca alamat itu sebagai nilai 32-bit, nilai 16-bit, atau nilai 8-bit. Pada mesin big endian, pointer menunjuk ke byte tinggi; pada mesin endian kecil, pointer menunjuk ke byte rendah.

Perhatikan bahwa ini semua tentang membaca dan menulis ke / dari memori. Ini tidak ada hubungannya dengan kode C / C ++ internal. Versi pertama dari kode, yang tidak dinyatakan sebagai C / C ++ tidak terdefinisi, akan selalu berfungsi untuk mendapatkan byte tinggi.

Masalahnya adalah ketika Anda mulai membaca stream byte. Seperti dari suatu file.

Nilai 16-bit memiliki masalah yang sama dengan nilai 32-bit; mereka hanya memiliki 2 byte, bukan 4. Oleh karena itu, file dapat berisi nilai 16-bit yang disimpan dalam urutan endian besar atau kecil.

UTF-16 didefinisikan sebagai urutan nilai 16-bit . Secara efektif, itu adalah uint16_t[]. Setiap unit kode individu memiliki nilai 16-bit. Oleh karena itu, untuk memuat UTF-16 dengan benar, Anda harus tahu apa kegunaan data itu.

UTF-8 didefinisikan sebagai urutan nilai 8-bit . Itu adalah uint8_t[]. Setiap unit kode individu berukuran 8-bit: satu byte.

Sekarang, baik UTF-16 dan UTF-8 memungkinkan untuk beberapa unit kode (nilai 16-bit atau 8-bit) untuk bergabung bersama untuk membentuk titik kode Unicode ("karakter", tapi itu bukan istilah yang benar; itu adalah penyederhanaan ). The rangka unit kode ini yang membentuk codepoint sebuah ditentukan oleh UTF-16 dan UTF-8 encoding.

Saat memproses UTF-16, Anda membaca nilai 16-bit, melakukan konversi endian apa pun yang diperlukan. Kemudian, Anda mendeteksi apakah itu pasangan pengganti; jika ya, maka Anda membaca nilai 16-bit lain, menggabungkan keduanya, dan dari sana, Anda mendapatkan nilai titik kode Unicode.

Saat memproses UTF-8, Anda membaca nilai 8-bit. Konversi endian tidak dimungkinkan, karena hanya ada satu byte. Jika byte pertama menunjukkan urutan multi-byte, maka Anda membaca beberapa jumlah byte, seperti yang ditentukan oleh urutan multi-byte. Setiap byte individu adalah byte dan karenanya tidak memiliki konversi endian. para rangka ini byte dalam urutan, seperti urutan pasangan pengganti di UTF-16, didefinisikan oleh UTF-8.

Jadi tidak ada masalah endian dengan UTF-8.

Nicol Bolas
sumber
10

Jawaban Jeremy Banks benar sejauh ini, tetapi tidak membahas pemesanan byte.

Ketika Anda menggunakan UTF-16, sebagian besar mesin terbang disimpan menggunakan kata dua-byte - tetapi ketika kata itu disimpan dalam file disk, urutan apa yang Anda gunakan untuk menyimpan byte konstituen?

Sebagai contoh, mesin terbang CJK (Cina) untuk kata "air" memiliki pengkodean UTF-16 dalam heksadesimal 6C34. Ketika Anda menulis itu sebagai dua byte ke disk, apakah Anda menuliskannya sebagai "big-endian" (dua byte tersebut adalah 6C 34)? Atau apakah Anda menulisnya sebagai "little-endian (dua byte adalah 34 6C)?

Dengan UTF-16, kedua pemesanan adalah sah, dan Anda biasanya menunjukkan yang mana dari file tersebut dengan membuat kata pertama dalam file menjadi Byte Order Mark (BOM), yang untuk pengkodean big-endian adalah FE FF, dan untuk little-endian encoding adalah FF FE.

UTF-32 memiliki masalah yang sama, dan solusi yang sama.

UTF-8 tidak memiliki masalah ini, karena itu panjang variabel, dan Anda secara efektif menulis urutan byte glyph seolah-olah itu adalah little-endian. Misalnya, huruf "P" selalu dikodekan menggunakan satu byte - 80 - dan karakter pengganti selalu dikodekan menggunakan dua byte FF FD dalam urutan itu.

Beberapa program menempatkan indikator tiga byte (EF BB BF) pada awal file UTF-8, dan itu membantu membedakan UTF-8 dari pengkodean serupa seperti ASCII, tetapi itu tidak terlalu umum kecuali pada MS Windows.

Bob Murphy
sumber
Terima kasih! (1) huruf "P" hanya satu byte di UTF-8. Mengapa karakter pengganti ditambahkan ke kode nya? (2) Di UTF-8, ada karakter lain yang memiliki lebih dari satu byte di UTF-8. Mengapa urutan byte antara byte untuk setiap karakter tersebut tidak menjadi masalah?
StackExchange for All
@Tim: (1) Anda tidak menambahkan karakter pengganti ke kode untuk P. Jika Anda melihat 80 FF FD, itu adalah dua karakter - karakter P, dan karakter pengganti.
Bob Murphy
(2) Anda selalu menulis dan membaca dua byte untuk "karakter pengganti" sebagai FF FD, dalam urutan itu. Hanya akan ada masalah pemesanan-byte jika Anda juga bisa menulis "karakter pengganti" sebagai FD FF - tetapi Anda tidak bisa; urutan dua byte itu akan menjadi sesuatu selain "karakter pengganti".
Bob Murphy
1
@Tim: Anda mungkin ingin bekerja melalui en.wikipedia.org/wiki/UTF-8 . Ini sangat bagus, dan jika Anda dapat memahami semua itu dan halaman Wikipedia lain yang terkait dengan Unicode, saya pikir Anda akan menemukan Anda tidak memiliki pertanyaan lagi tentang hal itu.
Bob Murphy
4
Alasan bahwa UTF-8 tidak memiliki masalah dengan urutan byte adalah bahwa pengkodean didefinisikan sebagai urutan byte , dan bahwa tidak ada variasi dengan endianness yang berbeda. Ini tidak ada hubungannya dengan panjang variabel.
starblue