UTF-8 neden kodlamasında birkaç bit israf ediyor?


17

Göre Wikipedia makalesinde , UTF-8 bu biçimdedir:

İlk kod Son kod Bayt Bayt 1 Bayt 2 Bayt 3 Bayt 4
point point Kullanılmış
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x, bu bitin kod noktasını seçmek için kullanıldığı anlamına gelir.

Bu, her devam baytında iki bit ve ilk baytta bir bit harcar. UTF-8 neden aşağıdaki gibi kodlanmamış?

İlk kod Son kod Bayt Bayt 1 Bayt 2 Bayt 3
point point Kullanılmış
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

Kod noktası Temel Çok Dilli Düzlemin dışında olduğunda veya kod noktası [U + 800, U + 3FFF] aralığında olduğunda bir bayt tasarruf eder.

UTF-8 neden daha verimli bir şekilde kodlanmıyor?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt Önerilen kodlamanız orijinal FSS / UTF teklifine benzer. Ken Thompson ve Rob Pike kendi kendini senkronize etmek istediler.
ninjalj

4
Ayrıca, kodlamanız ASCII kod değerlerinin ASCII olmayan karakterler için gösterimin hiçbir bölümünde görünmediğini garanti etmez. FSS / UTF ve UTF-8, eski programlarla çalışmak üzere tasarlanmıştır (örn: ASCII NUL kullanan ve ayırıcılar olarak eğik çizgi (yol ayırıcı)).
ninjalj

Yanıtlar:


26

Bu, çok baytlı bir dizinin ortasında olduğunuzu algılayabilmeniz için yapılır. UTF-8 verilerine baktığınızda, görüyorsanız 10xxxxxx, çokbaytlı bir karakterin ortasında olduğunuzu ve ya 0xxxxxxda görene kadar akışta yedekleneceğini bilirsiniz 11xxxxxx. Şemanızı kullanarak, bayt 2 veya 3 kolayca 0xxxxxxxveya11xxxxxx

Ayrıca ne kadar kaydedildiğinin tamamen ne tür bir dize verisini kodladığınıza bağlı olduğunu unutmayın. Çoğu metin, hatta Asya metni için, normal metin içeren dört baytlık karakterleri nadiren görürsünüz. Ayrıca, insanların metnin nasıl görüneceğine dair naif tahminleri genellikle yanlıştır. Japonca, Çince ve Korece dize içeren UTF-8 için yerelleştirilmiş metnim var, ancak aslında en fazla yer kaplayan Rus. (Asya dizelerimiz genellikle doğru isimler, noktalama işaretleri ve benzerleri için serpiştirilmiş Roma karakterlerine sahip olduğundan ve ortalama Rusça kelime çok fazla iken ortalama Çince kelime 1-3 karakter olduğu için.)


Ama benimle şemada, bir karakterin dilenci olduğu bilinen bir yerde başlarsanız, karakterde kaç bayt olduğunu söyleyebilir ve bir sonraki karakterin dilenmesine gidebilirsiniz.
qbt937

11
Elbette. Şemanız daha fazla bilgi yoğun ancak UTF-8'in sağladığı önemli bir özelliğe sahip değil. Genel olarak, insanlar güvenliği tercih eder, bu yüzden UTF-8 mümkündür. Ayrıca, planınızın gerçekten daha verimli olduğunu kanıtlamak için, gerçek metin kullanarak istatistik sağlamak istersiniz. Çoğu gerçek metinde, şemanızın çok önemsiz bir miktar tasarrufu sağladığını ve dolayısıyla tasarrufların buna değmeyeceğini görebilirsiniz.
Robotu Gort

3
Bir başka önemli özellik: Katıştırılmış sıfır kod noktası yoksa, dizede katıştırılmış sıfır yoktur.
Deduplicator

Tay dilinde komut dosyası için yazdırılan karakter başına 4 bayta izin vermeniz gerekir. Sadece partiye geç gelmekle kalmadılar ve çok sayıda kod grubu aldılar. Basıldığında tek bir karakter gibi görünen birçok şey aslında üç farklı unicode karakterden oluşur.
James Anderson

@ qbt937: Şemanızı kullanarak, bir dizenin diğerini içerip içermediğini öğrenmek için nasıl hızlı bir şekilde tararsınız?
supercat

6

O başlığın ortasında ve o bayt atlama (veya geriye doğru gidin) ile bayt başlayana kadar bilir ne zaman resmi yolu dekoder bilmesini sağlar 0veya 11; bu, tek bir bayt bozulduğunda çöp değerlerini önler.


3

Kısa cevap, teklifiniz ilk bayt ve devam baytları arasında ayrım yapmaz.

İlk baytın üst ucundaki bit deseni, gerçek karakterin kaç bayt olduğunu gösterir. Bu kalıplar ayrıca bir dizeyi ayrıştırırken bazı hata tanıma sağlar. Bir karakterin (görünüşte) ilk baytını okuyorsanız ve 10xxxxxx elde ediyorsanız, senkronizasyonunuzun bittiğini bilirsiniz.


2

Bahsedilmeyen şey, doğru bir kod noktası dizisine sahipseniz ve bir kod noktasının ilk baytını göstermesi garanti edilen bir işaretçiniz varsa, UTF-8 ile işaretçiyi ilk bayta kolayca bulabilirsiniz. önceki kod noktasının (01xx xxxx ile başlayan tüm baytları atla). Kodlamanızla, dizenin başlangıcına kadar olan tüm baytları potansiyel olarak incelemeden imkansızdır.

(2n + 2) bayt dizilerini göz önünde bulundurun

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

ve

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

Bu diziden sonraki ilk kod noktasının ilk baytına bir işaretçiniz varsa , son kod noktasının 0xxxxxxx veya (10xxxxxx, 0xxxxxxx) olup olmadığını öğrenmek için tüm baytları incelemelisiniz .

Aslında, daha önceki kod noktasına gitmenin sabit zamanda yapılabileceği ve bir kod noktasının ortasına işaretçiler düzeltilebilecek daha verimli kodlama şemaları vardır. Aşağıdaki kodlara izin verin:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

Önceki üç bayttan biri ≥ 236 ise, 3 baytlık bir dizinin başlangıcıdır, çünkü geçerli herhangi bir 3 baytlık dizide böyle iki bayt olamaz. Aksi takdirde, önceki iki bayttan biri ≥ 128 ise, iki baytlık bir dizinin başlangıcıdır. Aksi takdirde, önceki bayt tek bir bayttır <128.

Bir alt dize aramak biraz daha zorlaşır. Bir dizenin yalnızca sıfır kod noktası içeriyorsa sıfır bayt içermesi için sıfır baytı hariç tutmak isteyebilirsiniz.


Bahsetilmeyen şey - bu doğrudan @ratchet ucube'nin cevabında yapılan gözlemden kaynaklandığı için değil.
Piotr Dobrogost
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.