UTF-16 sabit genişlikli mi yoksa değişken genişlikli mi? UTF-8'in neden bayt sırası sorunu yok?


16
  1. UTF-16 sabit genişlikli mi yoksa değişken genişlikli mi? Farklı kaynaklardan farklı sonuçlar aldım:

    Gönderen http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :

    UTF-16, Unicode karakterlerini on altı bitlik yığınlarda saklar.

    Gönderen http://en.wikipedia.org/wiki/UTF-16/UCS-2 :

    UTF-16 (16 bit Unicode Dönüşüm Biçimi), Unicode kod alanında 0 ile 0x10FFFF arasında 1.112.064 [1] numara (kod noktası adı verilir) kodlayabilen bir karakter kodlamasıdır. Kod noktası başına bir veya iki 16 bit kod biriminin değişken uzunlukta bir sonucu üretir.

  2. İlk kaynaktan

    UTF-8'in ayrıca, kodlama biriminin bayt olması avantajı vardır, bu nedenle bayt sırası sorunları yoktur.

    UTF-8'in neden bayt sırası sorunu yok? Değişken genişliktedir ve bir karakter birden fazla bayt içerebilir, bu yüzden bayt sırasının hala bir sorun olabileceğini düşünüyorum?

Teşekkürler ve saygılar!


Bu harika makale Mutlak Minimum Her Yazılım Geliştiricisi Kesinlikle, Olumlu Unicode ve Karakter Setleri Hakkında Bilmeniz Gerekenler (Bahane Yok!) Unicode ve UTF ile ilgili tüm sorularınızı cevaplamanıza yardımcı olacaktır.
Sorceror

Yanıtlar:


13

(1) Bayt dizisi, C'deki bir karakterin aksine ne anlama gelir? UTF-16 bir bayt dizisi mi, yoksa ne olacak? (2) Bir bayt dizisinin neden değişken uzunlukla ilgisi yoktur?

Endian sorunlarının ne olduğunu yanlış anlıyorsunuz. İşte kısa bir özet.

32 bit tam sayı 4 bayt alır. Şimdi, bu baytların mantıksal sırasını biliyoruz. 32 bitlik bir tam sayıya sahipseniz, bunun yüksek baytını aşağıdaki kodla alabilirsiniz:

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

Hepsi iyi ve güzel. Sorunun başladığı yer, çeşitli donanımların tamsayıları bellekten nasıl sakladığı ve aldığı.

Big Endian düzeninde, 32 bit tam sayı olarak okuduğunuz 4 bayt bellek parçası ilk bayt yüksek bayt olacak şekilde okunacaktır:

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

Küçük Endian düzeninde, 32 bit tam sayı olarak okuduğunuz 4 bayt bellek parçası, ilk bayt düşük bayt olacak şekilde okunur :

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

32 bit değerine sahip bir işaretçiye işaretçiniz varsa, bunu yapabilirsiniz:

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

C / C ++ 'a göre, bunun sonucu tanımlanmamıştır. 0x81 olabilir. Veya 0x32 olabilir. Teknik olarak, her şeyi döndürebilir, ancak gerçek sistemler için birini veya diğerini döndürür.

Bellek adresini gösteren bir işaretçiniz varsa, bu adresi 32 bit değeri, 16 bit değeri veya 8 bit değeri olarak okuyabilirsiniz. Büyük bir endian makinesinde, işaretçi yüksek baytı gösterir; küçük bir endian makinesinde, işaretçi düşük bayta işaret eder.

Bunun tamamen belleğe okuma ve bellekten yazma ile ilgili olduğunu unutmayın. It has bir şey dahili C / C ++ kodu ile yapmak. Kodun ilk sürümü, C / C ++ 'nin tanımsız olarak bildirmediği, her zaman yüksek bayt almak için çalışacaktır.

Sorun bayt akışlarını okumaya başladığınız zamandır. Örneğin bir dosyadan.

16 bitlik değerler 32 bitlik değerlerle aynı sorunlara sahiptir; 4 yerine 2 bayt kullanırlar. Bu nedenle, dosya büyük endian veya küçük endian düzeninde depolanan 16 bitlik değerler içerebilir.

UTF-16, 16 bitlik değerler dizisi olarak tanımlanır . Etkili, bu bir uint16_t[]. Her bir kod birimi 16 bitlik bir değerdir. Bu nedenle, UTF-16'yı düzgün bir şekilde yüklemek için verilerin endianitesinin ne olduğunu bilmelisiniz.

UTF-8, 8 bitlik değerler dizisi olarak tanımlanır . Bu bir uint8_t[]. Her bir kod birimi 8 bit boyutundadır: tek bir bayt.

Şimdi, hem UTF-16 hem de UTF-8, birden çok kod biriminin (16 bit veya 8 bit değerler) bir Unicode kod noktası (bir "karakter" oluşturmak için bir araya gelmesine izin veriyor, ancak bu doğru terim değil ; bu bir basitleştirme) ). Sipariş bir codepoint oluşturan bu kod birimi UTF-16 ve UTF-8 kodlaması ile belirlenir.

UTF-16 işlenirken 16 bit bir değer okursunuz ve gerekli endian dönüşümü yapılır. Sonra, bunun vekil bir çift olup olmadığını tespit edersiniz; öyleyse, başka bir 16 bit değer okur, ikisini birleştirirsiniz ve bundan Unicode kod noktası değerini alırsınız.

UTF-8'i işlerken 8 bitlik bir değer okursunuz. Yalnızca bir bayt olduğundan endian dönüşümü mümkün değildir. İlk bayt çok baytlı bir sekansı gösteriyorsa, çok baytlı sekans tarafından dikte edildiği gibi bir takım baytları okursunuz. Her ayrı bayt bir bayttır ve bu nedenle endian dönüşümü yoktur. Sipariş Bunların UTF-16 surrogate çiftlerinin sırası, UTF-8 ile tanımlanan gibi, sırayla bayt.

Dolayısıyla UTF-8 ile ilgili endian sorunları olamaz.


10

Jeremy Banks'ın cevabı gittikçe doğru, ancak bayt sırasını ele almadı.

UTF-16 kullandığınızda, çoğu glif iki baytlık bir kelime kullanılarak saklanır - ancak kelime bir disk dosyasında saklandığında, kurucu baytları depolamak için hangi sırayı kullanırsınız?

Örnek olarak, "su" kelimesi için CJK (Çince) glifinin, onaltılık 6C34 kodlamalı bir UTF-16 kodlaması vardır. Bunu diske iki bayt olarak yazdığınızda, "big-endian" olarak yazarsınız (iki bayt 6C 34'tür)? Yoksa "küçük endian (iki bayt 34 6C) mı?

UTF-16 ile, her iki sıralama da meşrudur ve genellikle dosyadaki ilk kelimeyi, büyük endian kodlaması için FE FF ve küçük endian için bir Bayt Sırası İşareti (BOM) yaparak belirtiniz. kodlama FF FE'dir.

UTF-32'de aynı sorun ve aynı çözüm vardır.

UTF-8'in bu sorunu yoktur, çünkü değişken uzunluktadır ve bir glifin bayt dizisini küçük bir endianmış gibi etkili bir şekilde yazarsınız. Örneğin, "P" harfi her zaman bir bayt - 80 - kullanılarak değiştirilir ve değiştirme karakteri her zaman iki bayt FF FD kullanılarak bu sırayla kodlanır.

Bazı programlar UTF-8 dosyasının başına üç baytlık bir gösterge (EF BB BF) yerleştirir ve bu UTF-8'i ASCII gibi benzer kodlamalardan ayırmaya yardımcı olur, ancak MS Windows dışında çok yaygın değildir.


Teşekkürler! (1) "P" harfi UTF-8'de sadece bir bayttır. Yedek karakter neden koduna eklenir? (2) UTF-8'de, UTF-8'de birden fazla bayta sahip başka karakterler var. Bu karakterlerin her biri için baytlar arasındaki bayt sırası neden sorun değil?
Tim

@Tim: (1) P koduna yedek karakteri eklemezsiniz. 80 FF FD görürseniz, bu iki karakterdir - bir P karakteri ve bir yedek karakter.
Bob Murphy

(2) "Yedek karakter" için iki baytı her zaman bu sırayla FF FD olarak yazar ve okursunuz. Bir bayt sırası sorunu yalnızca "yedek karakteri" FD FF olarak da yazabilseydiniz - ancak yapamazsınız; bu iki baytlık dizilim "yerine koyma karakteri" dışında bir şey olabilir.
Bob Murphy

1
@Tim: en.wikipedia.org/wiki/UTF-8 aracılığıyla çalışmak isteyebilirsiniz . Gerçekten çok iyi ve hepsini ve Unicode ile ilgili diğer Wikipedia sayfalarını anlayabiliyorsanız, bence bu konuda başka sorunuz yok.
Bob Murphy

4
UTF-8'in bayt sırası ile herhangi bir sorunu olmamasının nedeni, kodlamanın bir bayt dizisi olarak tanımlanmış olması ve farklı endianiteye sahip hiçbir varyasyon olmamasıdır. Değişken uzunluk ile ilgisi yoktur.
starblue
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.