Ile znaków można zakodować w UTF-8?


97

Jeśli UTF-8 ma 8 bitów, czy nie oznacza to, że może istnieć tylko maksymalnie 256 różnych znaków?

Pierwsze 128 punktów kodowych jest takich samych jak w ASCII. Ale mówi, że UTF-8 może obsługiwać do miliona znaków?

Jak to działa?


2
czy mógłbyś ponownie ocenić to pytanie, ponieważ wszystkie odpowiedzi są błędne. Przeczytaj moją odpowiedź: stackoverflow.com/a/45042566/124486
Evan Carroll

W kodowaniu Unicode UTF-8, UTF-16, UTF-32 liczba jest liczbą bitów w jednostkach kodu , z których jeden lub więcej koduje punkt kodowy Unicode.
Tom Blodget

1
Odpowiedziałem na to pytanie jakiś czas temu, próbując je wyprostować: byłoby wspaniale, gdybyś zważył to z wybraną odpowiedzią, która jest dosłownie jednym cytatem z Wikipedii, który nie mówi całej historii (mam nadzieję, że moja aktualizacja jest dużo jaśniejsze)
Evan Carroll,

Odpowiedzi:


135

UTF-8 nie używa przez cały czas jednego bajtu, ma od 1 do 4 bajtów.

Pierwsze 128 znaków (US-ASCII) wymaga jednego bajtu.

Kolejne 1920 znaków wymaga do zakodowania dwóch bajtów. Dotyczy to pozostałej części prawie wszystkich alfabetów łacińskich, a także alfabetów greckiego, cyrylicy, koptyjskiego, ormiańskiego, hebrajskiego, arabskiego, syryjskiego i tana, a także łączonych znaków diakrytycznych.

Trzy bajty są potrzebne na znaki w pozostałej części podstawowej płaszczyzny wielojęzycznej, która zawiera praktycznie wszystkie powszechnie używane znaki [12], w tym większość znaków chińskich, japońskich i koreańskich [CJK].

Cztery bajty są potrzebne dla znaków w innych płaszczyznach Unicode, które obejmują mniej powszechne znaki CJK, różne historyczne skrypty, symbole matematyczne i emoji (symbole piktograficzne).

źródło: Wikipedia


cześć @zwippie, nowy w tym. Jest coś, czego nie rozumiem.! BMP wykorzystuje 2 bajty, o których mówisz, że to 3? czy się mylę?
chiperortiz

1
@chiperortiz, BMP ma rzeczywiście 16 bitów, więc można go zakodować jako UTF-16 ze stałą długością na znak (UTF-16 obsługuje również przekraczanie 16 bitów, ale jest to trudna praktyka i wiele implementacji go nie obsługuje). Jednak w przypadku UTF-8 musisz również zakodować, jak długo to będzie, więc tracisz trochę bitów. Dlatego potrzebujesz 3 bajtów, aby zakodować cały plik BMP. Może się to wydawać marnotrawstwem, ale pamiętaj, że UTF-16 zawsze wykorzystuje 2 bajty, ale UTF-8 wykorzystuje jeden bajt na znak dla większości znaków języka łacińskiego. Dzięki temu jest dwa razy mniejszy.
sanderd17

Główny wątek pytania PO jest związany z tym, dlaczego nazywa się UTF- 8 - to tak naprawdę nie odpowiada.
jbyrd

40

UTF-8 wykorzystuje od 1 do 4 bajtów na znak: jeden bajt na znaki ascii (pierwsze 128 wartości Unicode jest takich samych jak ascii). Ale to wymaga tylko 7 bitów. Jeśli ustawiony jest najwyższy („znak”) bit, oznacza to początek sekwencji wielobajtowej; liczba kolejnych starszych bitów wskazuje liczbę bajtów, następnie 0, a pozostałe bity składają się na wartość. W przypadku pozostałych bajtów najwyższe dwa bity będą miały wartość 1 i 0, a pozostałe 6 bitów będzie stanowić wartość.

Zatem czterobajtowa sekwencja zaczynałaby się od 11110 ... (i ... = trzy bity dla wartości), a następnie trzy bajty po 6 bitów na wartość, dając 21-bitową wartość. 2 ^ 21 przekracza liczbę znaków Unicode, więc cały Unicode można wyrazić w UTF8.


@NickL. Nie, mam na myśli 3 bajty. W tym przykładzie, jeśli pierwszy bajt wielobajtowej sekwencji zaczyna się od 1111, pierwsza 1 wskazuje, że jest to początek wielobajtowej sekwencji, a następnie liczba kolejnych jedynek po niej wskazuje liczbę dodatkowych bajtów w sekwencji (czyli pierwsza bajt rozpocznie się od 110, 1110 lub 11110).
CodeClown42,

Znalazłem dowód na twoje słowa w RFC 3629. tools.ietf.org/html/rfc3629#section-3 . Jednak nie rozumiem, dlaczego muszę umieścić „10” na początku drugiego bajtu 110xxxxx 10xxxxxx? Dlaczego nie tylko 110xxxxx xxxxxxxx?
kolobok

3
Znaleziono odpowiedź w softwareengineering.stackexchange.com/questions/262227/… . Tylko ze względów bezpieczeństwa (w przypadku pojedynczy bajt w środku strumienia jest uszkodzona)
Kolobok

@kolobok Ah. Bez bezpieczeństwa możesz następnie zakodować 21-bitową wartość w 3 bajtach (3 bity wskazujące długość plus 21 bitów). : D Prawdopodobnie nie jest to jednak tak znaczące, przynajmniej w zachodnich językach WRT.
CodeClown42,

Zgaduję, że NickL zadał to pytanie, ale co się stało z resztą bitów w tym pierwszym bajcie, jeśli… reprezentuje kolejne bajty zamiast bitów?
c6754

27

Zgodnie z tą tabelą * UTF-8 powinien obsługiwać:

2 31 = 2 147 483 648 znaków

Jednak RFC 3629 ograniczył możliwe wartości, więc teraz jesteśmy ograniczone do 4 bajtów , co daje nam

2 21 = 2097152 znaków

Zwróć uwagę, że spora część tych znaków jest „zarezerwowana” do użytku niestandardowego, co jest całkiem przydatne w przypadku czcionek z ikonami.

* Użyta Wikipedia pokazuje tabelę z 6 bajtami - od tego czasu zaktualizowali artykuł.

2017-07-11: Poprawiono podwójne liczenie tego samego punktu kodowego zakodowanego wieloma bajtami


Ta odpowiedź to podwójne policzenie liczby możliwych kodowań. Gdy policzysz wszystkie 2 ^ 7, nie możesz policzyć ich ponownie w 2 ^ 11, 2 ^ 16 itd. Prawidłowa liczba możliwych kodowań to 2 ^ 21 (chociaż nie wszystkie są obecnie używane).
Jimmy

@Jimmy Na pewno liczę podwójnie? 0xxxxxxxdaje 7 użytecznych bitów, 110xxxxx 10xxxxxxdaje 11 więcej - nie ma nakładania się. Pierwszy bajt zaczyna się 0w pierwszym przypadku, aw 1drugim przypadku.
mpen

@mpen więc jaki punkt kodu 00000001przechowuje, a co 11000000 100000001przechowuje?
Evan Carroll,

1
@EvanCarroll Uhh .... punkt zajęty. Nie zdawałem sobie sprawy, że istnieje wiele sposobów zakodowania tego samego punktu kodowego.
mpen

1
Poszedłem naprzód i spróbowałem odpowiedzieć na to sam, zobacz, czy uważasz, że to lepsze wyjaśnienie i odpowiedź na pytanie: stackoverflow.com/a/45042566/124486
Evan Carroll

21

Unicode vs UTF-8

Unicode zamienia punkty kodowe na znaki. UTF-8 to mechanizm przechowywania danych dla Unicode. Unicode ma specyfikację. UTF-8 ma specyfikację. Obaj mają różne ograniczenia. UTF-8 ma inne ograniczenie w górę.

Unicode

Unicode jest oznaczony jako „płaszczyzny”. Każdy samolot przenosi 2 16 punktów kodowych. W Unicode jest 17 samolotów. Suma 17 * 2^16punktów kodowych. Pierwszy samolot, samolot 0 lub BMP , jest szczególny w stosunku do masy, co niesie.

Zamiast wyjaśniać wszystkie niuanse, zacytuję tylko powyższy artykuł o samolotach.

17 płaszczyzn może pomieścić 1 114 112 punktów kodowych. Spośród nich 2048 to surogaty, 66 nie jest znakami, a 137 468 jest zarezerwowanych do użytku prywatnego, pozostawiając 974,530 do publicznego przypisania.

UTF-8

Wróćmy teraz do powyższego artykułu,

Schemat kodowania używany przez UTF-8 został zaprojektowany z dużo większym limitem 2 31 punktów kodowych (32768 płaszczyzn) i może zakodować 2 21 punktów kodowych (32 płaszczyzny), nawet jeśli jest ograniczony do 4 bajtów. [3] Ponieważ Unicode ogranicza punkty kodowe do 17 płaszczyzn, które mogą być kodowane przez UTF-16, punkty kodowe powyżej 0x10FFFF są nieważne w UTF-8 i UTF-32.

Widzisz więc, że możesz umieścić w UTF-8 rzeczy, które nie są poprawnym Unicode. Czemu? Ponieważ UTF-8 obsługuje punkty kodowe, których Unicode nawet nie obsługuje.

UTF-8, nawet z ograniczeniem do czterech bajtów, obsługuje 2 21 punktów kodowych, czyli znacznie więcej niż17 * 2^16


19

2.164.864 „znaków” może być potencjalnie zakodowanych przez UTF-8.

Ta liczba to 2 ^ 7 + 2 ^ 11 + 2 ^ 16 + 2 ^ 21, co wynika ze sposobu działania kodowania:

  • 0xxxxxxxZnaki 1-bajtowe mają 7 bitów do kodowania (0x00-0x7F)

  • 2-bajtowe znaki mają 11 bitów do kodowania 110xxxxx 10xxxxxx(0xC0-0xDF dla pierwszego bajtu; 0x80-0xBF dla drugiego)

  • 1110xxxx 10xxxxxx 10xxxxxxZnaki 3-bajtowe mają 16 bitów do kodowania (0xE0-0xEF dla pierwszego bajtu; 0x80-0xBF dla bajtów kontynuacji)

  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxZnaki 4-bajtowe mają 21 bitów do kodowania (0xF0-0xF7 dla pierwszego bajtu; 0x80-0xBF dla bajtów kontynuacji)

Jak widać, jest to znacznie więcej niż obecny Unicode (1112 064 znaków).

AKTUALIZACJA

Moje wstępne obliczenia są błędne, ponieważ nie uwzględniają dodatkowych reguł. Więcej szczegółów można znaleźć w komentarzach do tej odpowiedzi.


2
Twoja matematyka nie respektuje reguły UTF-8, zgodnie z którą tylko najkrótsza sekwencja jednostek kodu może zakodować punkt kodowy. Tak więc 00000001 obowiązuje dla U + 0001, ale 11110000 10000000 10000000 10000001 nie. Odn .: Tabela 3-7. Dobrze sformatowane sekwencje bajtów UTF-8 . Poza tym na pytanie bezpośrednio odpowiada tabela: wystarczy zsumować zakresy. (Są rozłączne, aby wykluczyć substytuty dla UTF-16).
Tom Blodget

Tom - dzięki za komentarz! Nie zdawałem sobie sprawy z tych ograniczeń. Zobaczyłem tabelę 3-7 i sprawdziłem liczby i wygląda na to, że istnieje 1,083,392 możliwych prawidłowych sekwencji.
Ruben Reyes

6

UTF-8 to kodowanie o zmiennej długości z minimum 8 bitami na znak.
Znaki z wyższymi punktami kodowymi zajmują do 32 bitów.


2
To jest mylące. Najdłuższy punkt kodowy, jaki możesz mieć, to 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, więc tylko 21 bitów może być użyte do zakodowania rzeczywistego znaku.
Boris

5
Powiedziałem, że zakodowanie punktów kodowych może zająć do 32 bitów, nigdy nie twierdziłem, że (przez indukcję) można zakodować 2 ^ 32 znaki w 32-bitowym UTF-8. Ale to jest raczej dyskusyjna, ponieważ można kodować wszystkie istniejące znaki Unicode UTF-8, a może kodować nawet więcej, jeśli rozciągnąć UTF-8 do 48 bitów (co istnieje, ale jest przestarzałe), więc nie jestem pewien, co jest to mylący punkt.
deceze


2

Sprawdź standard Unicode i powiązane informacje, takie jak wpis w często zadawanych pytaniach, UTF-8, UTF-16, UTF-32 i BOM . To nie jest takie płynne żeglowanie, ale to wiarygodne informacje, a wiele z tego, co można przeczytać o UTF-8 gdzie indziej, jest wątpliwe.

„8” w „UTF-8” odnosi się do długości jednostek kodu w bitach. Jednostki kodu to jednostki używane do kodowania znaków, niekoniecznie jako proste mapowanie jeden do jednego. UTF-8 używa zmiennej liczby jednostek kodu do kodowania znaku.

Zbiór znaków, które można zakodować w UTF-8 jest dokładnie taki sam jak w przypadku UTF-16 lub UTF-32, a mianowicie wszystkie znaki Unicode. Wszystkie kodują całą przestrzeń kodowania Unicode, która obejmuje nawet znaki niebędące znakami i nieprzypisane punkty kodowe.


1

Chociaż zgadzam się z mpen w sprawie obecnych maksymalnych kodów UTF-8 (2164864) (wymienionych poniżej, nie mogłem skomentować jego), jest on wyłączony o 2 poziomy, jeśli usuniesz 2 główne ograniczenia UTF-8: tylko 4 bajty limitu i kodów 254 i 255 nie można użyć (usunął tylko limit 4-bajtowy).

Kod startowy 254 jest zgodny z podstawowym układem bitów początkowych (wielobitowa flaga ustawiona na 1, liczba 6 jedynek i terminal 0, brak zapasowych bitów), co daje 6 dodatkowych bajtów do pracy (6 grup 10xxxxxx, dodatkowe 2 ^ 36 kodów).

Początkowy kod 255 nie jest dokładnie zgodny z podstawową konfiguracją, nie ma terminala 0, ale używane są wszystkie bity, co daje 7 dodatkowych bajtów (flaga wielobitowa ustawiona na 1, liczba 7 1 i brak terminala 0, ponieważ wszystkie bity są używane ; 7 grup 10xxxxxx, dodatkowe 2 ^ 42 hasła).

Dodanie ich daje ostateczny maksymalny zestaw znaków, który można przedstawić, wynoszący 4468982745216. To więcej niż wszystkie znaki w obecnym użyciu, stare lub martwe języki oraz wszelkie języki, które uważa się za utracone. Anielski lub niebiański scenariusz jest ktoś?

Istnieją również kody jednobajtowe, które są pomijane / ignorowane w standardzie UTF-8 oprócz 254 i 255: 128-191 i kilku innych. Niektóre są używane lokalnie przez klawiaturę, przykładowy kod 128 to zwykle usuwający backspace. Inne kody początkowe (i związane z nimi zakresy) są nieprawidłowe z co najmniej jednego powodu ( https://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences ).


0

Unicode jest mocno związany z UTF-8. Unicode obsługuje 2 ^ 21 punktów kodowych (2097152 znaków), czyli dokładnie tyle samo punktów kodowych, ile obsługuje UTF-8. Oba systemy rezerwują tę samą „martwą” przestrzeń i strefy ograniczone dla punktów kodowych itp. ... od czerwca 2018 najnowsza wersja, Unicode 11.0, zawiera repertuar 137.439 znaków

Ze standardu Unicode. Często zadawane pytania dotyczące Unicode

Standard Unicode koduje znaki z zakresu U + 0000..U + 10FFFF, co odpowiada 21-bitowej przestrzeni kodowej.

Ze strony Wikipedii UTF-8. Opis UTF-8

Od czasu ograniczenia przestrzeni kodowej Unicode do wartości 21-bitowych w 2003 r., UTF-8 jest zdefiniowany do kodowania punktów kodowych w jednym do czterech bajtów, ...


21 bitów jest zaokrąglanych w górę. Unicode obsługuje 1,114,112 punktów kodowych (od U ​​+ 0000 do U + 10FFFF), jak jest napisane. (Czasami opisywane jako 17 samolotów 65536.)
Tom Blodget,

@TomBlodget, masz rację. najważniejszym wnioskiem z tej dyskusji jest to, że UTF-8 może zakodować wszystkie aktualnie zdefiniowane punkty w standardzie Unicode i prawdopodobnie będzie w stanie to zrobić przez dłuższy czas.
Wyświetlana nazwa
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.