Ile bajtów zajmuje jeden znak Unicode?

239

Jestem trochę zdezorientowany co do kodowania. O ile wiem, stare znaki ASCII zajmowały jeden bajt na znak. Ile bajtów wymaga znak Unicode?

Zakładam, że jeden znak Unicode może zawierać każdy możliwy znak z dowolnego języka - czy mam rację? Ile bajtów potrzebuje na znak?

A co oznaczają UTF-7, UTF-6, UTF-16 itd.? Czy są to różne wersje Unicode?

Czytałem artykuł w Wikipedii o Unicode, ale jest to dla mnie dość trudne. Nie mogę się doczekać prostej odpowiedzi.

nan
źródło
15
Przepraszamy, nie ma prostej odpowiedzi. Cała sprawa jest dla mnie trochę bałaganu. Unicode został rozliczony jako wykorzystujący dwa bajty i mogący reprezentować wszystkie znaki, ale okazuje się, że dwa bajty to za mało.
Jonathan Wood
12
„Prosta odpowiedź”: znak Unicode zajmuje 1-4 bajty. Unicode obejmuje wiele języków, ale nie wszystkie. Kiedy ostatnio patrzyłem, na przykład Klingon nie był oficjalnym zestawem znaków Unicode.
Peter G.
9
Klingon nie jest częścią samego standardu Unicode, nie. Zamiast tego używa prywatnego obszaru Uniode (U + F8D0 - U + F8FF).
Remy Lebeau
1
Pytanie Zbawiciela - dzięki. Moja sytuacja polega na przechowywaniu danych za pomocą LMS zgodnych z SCORM 1.2 ... standard dla SCORM 1.2 'cmi.suspend_data' to 4096 bajtów danych, które, jak zakładał poprzedni programista, oznaczały, że możemy przechowywać 4096 znaków. O rany, mylił się - właśnie odkryłem, dlaczego nasze zakładki zawodzą na długich kursach. Teraz wiem, że ponieważ używamy UTF-8, potrzeba 4 bajtów na znak, co daje nam 1024 znaki.
danjah

Odpowiedzi:

147

Nie zobaczysz prostej odpowiedzi, ponieważ nie ma takiej.

Po pierwsze, Unicode nie zawiera „wszystkich znaków z każdego języka”, chociaż na pewno próbuje.

Sam Unicode jest odwzorowaniem, definiuje punkty kodowe, a punkt kodowy jest liczbą związaną zwykle ze znakiem. Mówię zwykle, ponieważ istnieją pojęcia takie jak łączenie postaci. Możesz być zaznajomiony z akcentami lub umlautami. Można ich użyć z innym znakiem, takim jak a alub a, uaby utworzyć nowy znak logiczny. Postać może zatem składać się z 1 lub więcej współrzędnych kodowych.

Aby być użytecznym w systemach komputerowych, musimy wybrać reprezentację dla tych informacji. Są to różne kodowania Unicode, takie jak utf-8, utf-16le, utf-32 itd. Różnią się one w dużej mierze rozmiarem ich jednostek kodowych. UTF-32 jest najprostszym kodowaniem, ma 32-bitową jednostkę kodową, co oznacza, że ​​pojedynczy punkt kodowy wygodnie pasuje do jednostki kodowej. Inne kodowania będą miały sytuacje, w których punkt kodowy będzie wymagał wielu jednostek kodowych lub ten konkretny punkt kodowy nie będzie w ogóle reprezentowany w kodowaniu (jest to na przykład problem z UCS-2).

Ze względu na elastyczność łączenia znaków, nawet w ramach danego kodowania, liczba bajtów na znak może się różnić w zależności od znaku i formy normalizacji. Jest to protokół postępowania ze znakami, które mają więcej niż jedną reprezentację (możesz powiedzieć, "an 'a' with an accent"które są 2 kodowymi punktami, z których jeden jest znakiem łączącym lub "accented 'a'"który jest jednym kodowym).

Logan Capaldo
źródło
1
DOBRZE. Ile bajtów zajmuje jeden dany znak reprezentowany w jednym danym punkcie kodowym? Na przykład przestrzeń niełamliwa.
Nicolas Barbulesco
Łączenie znaków sprawia, że ​​życie programisty jest piekłem, jeśli chodzi o pisanie strlen (), substr () i innych funkcji manipulacji ciągami na tablicach UTF8. Tego rodzaju praca nigdy nie będzie ukończona i zawsze będzie błędna.
Nulik
Napisałem demo, które pokazuje pliki zakodowane w Windows-1252, UTF8 i UTF8-BOM interpretowane przy każdym kodowaniu i porównuje równość wyników: github.com/vladyrn/encodings_demo
Vlad
195

O dziwo, nikt nie wskazał, jak obliczyć, ile bajtów zajmuje jeden znak Unicode. Oto reguła dla łańcuchów kodowanych w UTF-8:

Binary    Hex          Comments
0xxxxxxx  0x00..0x7F   Only byte of a 1-byte character encoding
10xxxxxx  0x80..0xBF   Continuation byte: one of 1-3 bytes following the first
110xxxxx  0xC0..0xDF   First byte of a 2-byte character encoding
1110xxxx  0xE0..0xEF   First byte of a 3-byte character encoding
11110xxx  0xF0..0xF7   First byte of a 4-byte character encoding

Szybka odpowiedź brzmi: zajmuje 1 do 4 bajtów, w zależności od pierwszego, który wskaże, ile bajtów zajmie.

paul.ago
źródło
8
Uważam, że maksymalna wartość szesnastkowa dla 4-bajtowego znaku wynosi 0xF7 (nie 0xF4).
DJPJ
Dziękuję bardzo! Właśnie kontrolowałem + f'ing przez standard IETF i nie znalazłem nic na temat kodowania, a artykuł, który czytałem, nie zawierał wystarczająco dużo szczegółów, aby powiedzieć, ile bitów jest używanych do reprezentowania liczby końcowego kodu punktów za „znak”.
MarcusJ
1
To jest teraz na drugiej stronie ściągawki „wprowadzenie dla nowych członków zespołu”, a także przez zabawne pierwsze dwa komentarze
Cee McSharpface,
1
0xF4 nie był pomyłką, ale wyjaśnieniem. Punkty kodowe Unicode mieszczą się w zakresie 0-0x10ffff, więc ostatni punkt kodowy jest kodowany jako F4 8F BF BF.
Frediano Ziglio
38

Wiem, że to pytanie jest stare i ma już zaakceptowaną odpowiedź, ale chcę podać kilka przykładów (mam nadzieję, że będzie komuś przydatny).

O ile wiem, stare znaki ASCII zajmowały jeden bajt na znak.

Dobrze. W rzeczywistości, ponieważ ASCII jest kodowaniem 7-bitowym, obsługuje 128 kodów (z których 95 można wydrukować), więc wykorzystuje tylko pół bajtu (jeśli to ma sens).

Ile bajtów wymaga znak Unicode?

Unicode po prostu mapuje znaki na punkty kodowe. Nie określa, jak je zakodować. Plik tekstowy nie zawiera znaków Unicode, ale bajty / oktety, które mogą reprezentować znaki Unicode.

Zakładam, że jeden znak Unicode może zawierać każdy możliwy znak z dowolnego języka - czy mam rację?

Nie. Ale prawie. W zasadzie tak. Ale nadal nie.

Ile bajtów potrzebuje na znak?

To samo co twoje drugie pytanie.

A co oznaczają UTF-7, UTF-6, UTF-16 itp.? Czy są to jakieś wersje Unicode?

Nie, to są kodowania. Określają, w jaki sposób bajty / oktety powinny reprezentować znaki Unicode.

Kilka przykładów. Jeśli niektórych z nich nie można wyświetlić w przeglądarce (prawdopodobnie dlatego, że czcionka ich nie obsługuje), przejdź do http://codepoints.net/U+1F6AA(zamień 1F6AAna współrzędną kodową w hex), aby zobaczyć obraz.

    • U + 0061 ŁACIŃSKI MAŁY LIST A: a
      • Nº: 97
      • UTF-8: 61
      • UTF-16: 00 61
    • U + 00A9 ZNAK PRAWA AUTORSKIEGO: ©
      • Nº: 169
      • UTF-8: C2 A9
      • UTF-16: 00 A9
    • U + 00AE ZAREJESTROWANY ZNAK: ®
      • Nº: 174
      • UTF-8: C2 AE
      • UTF-16: 00 AE
    • U + 1337 ETIOPTYCZNY SYGNAŁ PHWA:
      • Nº: 4919
      • UTF-8: E1 8C B7
      • UTF-16: 13 37
    • U + 2014 EM DASH:
      • Nº: 8212
      • UTF-8: E2 80 94
      • UTF-16: 20 14
    • U + 2030 NA MILLE SIGN:
      • Nº: 8240
      • UTF-8: E2 80 B0
      • UTF-16: 20 30
    • U + 20AC ZNAK EURO:
      • Nº: 8364
      • UTF-8: E2 82 AC
      • UTF-16: 20 AC
    • U + 2122 ZNAK ZNAKU TOWAROWEGO:
      • Nº: 8482
      • UTF-8: E2 84 A2
      • UTF-16: 21 22
    • U + 2603 SNOWMAN:
      • Nº: 9731
      • UTF-8: E2 98 83
      • UTF-16: 26 03
    • U + 260E CZARNY TELEFON:
      • Nº: 9742
      • UTF-8: E2 98 8E
      • UTF-16: 26 0E
    • U + 2614 PARASOL Z KROPLI DESZCZU:
      • Nº: 9748
      • UTF-8: E2 98 94
      • UTF-16: 26 14
    • U + 263A BIAŁA TWARZ UŚMIECHNIĘTY:
      • Nº: 9786
      • UTF-8: E2 98 BA
      • UTF-16: 26 3A
    • U + 2691 BLACK FLAG:
      • Nº: 9873
      • UTF-8: E2 9A 91
      • UTF-16: 26 91
    • U + 269B SYMBOL ATOMOWY:
      • Nº: 9883
      • UTF-8: E2 9A 9B
      • UTF-16: 26 9B
    • U + 2708 SAMOLOT:
      • Nº: 9992
      • UTF-8: E2 9C 88
      • UTF-16: 27 08
    • U + 271E CIENIANY BIAŁY KRZYŻ ŁACIŃSKI:
      • Nº: 10014
      • UTF-8: E2 9C 9E
      • UTF-16: 27 1E
    • U + 3020 POSTAL MARK TWARZ:
      • Nº: 12320
      • UTF-8: E3 80 A0
      • UTF-16: 30 20
    • U + 8089 CJK UNIFIED IDEOGRAPH-8089:
      • Nº: 32905
      • UTF-8: E8 82 89
      • UTF-16: 80 89
    • U + 1F4A9 PILE OF POO: 💩
      • Nº: 128169
      • UTF-8: F0 9F 92 A9
      • UTF-16: D8 3D DC A9
    • ROCKET U + 1F680: 🚀
      • Nº: 128640
      • UTF-8: F0 9F 9A 80
      • UTF-16: D8 3D DE 80

Dobra, daję się ponieść ...

Zabawne fakty:

podstawowy 6
źródło
Jednostki kodu w UTF-16 mają 16 bitów szerokości. Pokazałeś im spację na środku, co jest mylące. Reprezentacja UTF-16 dla © powinna raczej być 00A9zamiast 00 A9(która byłaby UTF-16BE).
Roland Illig
Co za różnica? Czy BE nie oznacza big endian? Napisał to w big endian, więc plik napisany w big endian UTF-16 byłby taki sam jak UTF-16BE, prawda?
HappyPandaFace
6
Poprawki: 1) ASCII ma 7 bitów, bajt ma 8 bitów, więc jest o wiele więcej niż połową. 2) Unicode nie definiuje sposobu kodowania punktów kodowych. UTF-8, UTF-16 i UTF-32 są zdefiniowane w standardzie Unicode.
Jonathan Rosenne
3
@JonathanRosenne Myślę, że on / on miał na myśli, że używa tylko połowy możliwych wartości reprezentowanych przez 8 bitów, a nie, że używa połowy bitów.
Aritz Lopez
2
Naprawdę lubię przykłady. Podkreślają na przykład, dlaczego można preferować UTF-16 niż UTF-8. Twórcy różnych programów mogą wybierać różne kodowania, na podstawie których bardziej prawdopodobne jest użycie znaków Unicode. Na przykład w Chinach / Japonii UTF-16 (2 bajty) ma dla nich więcej sensu niż UTF-8, ponieważ te same znaki często potrzebują dwa razy więcej bajtów do zakodowania w UTF-8
Mike
29

Mówiąc wprost, Unicodejest standardem, który przypisuje jeden numer (zwany punktem kodowym) wszystkim postaciom świata (wciąż trwa).

Teraz musisz reprezentować ten kod za pomocą bajtów, tak zwanych character encoding. UTF-8, UTF-16, UTF-6to sposoby reprezentowania tych postaci.

UTF-8to wielobajtowe kodowanie znaków. Znaki mogą mieć od 1 do 6 bajtów (niektóre z nich mogą być w tej chwili niepotrzebne).

UTF-32 każdy znak ma 4 bajty na znak.

UTF-16używa 16 bitów na każdy znak i reprezentuje tylko część znaków Unicode o nazwie BMP (dla wszystkich praktycznych celów wystarczy). Java używa tego kodowania w swoich ciągach.

Zimbabao
źródło
10
Unicode to 21-bitowy zestaw kodów, a 4 bajty wystarczają do przedstawienia dowolnego znaku Unicode w UTF-8. UTF-16 używa surogatów do reprezentowania znaków poza BMP (podstawowa płaszczyzna wielojęzyczna); potrzebuje 2 lub 4 bajtów do przedstawienia dowolnego poprawnego znaku Unicode. UCS-2 był 16-bitowym wariantem UTF-16 bez wsparcia dla surogatów lub znaków spoza BMP.
Jonathan Leffler
1
Masz rację. Oryginalny UTF-8 miał 6 bajtów na 32 bit. Właściwie to nie chciałem komplikować rzeczy, ponieważ był już mylony z dokumentacją wiki :)
Zimbabao,
3
Ta odpowiedź stwierdza, że ​​UTF-16 nie może kodować punktów kodowych BMP. Jest to niepoprawne, ponieważ można je zakodować tak samo, jak w UTF-8 przy użyciu par zastępczych. (Musisz myśleć o przestarzałym UCS-2, zanim pojawił się Unicode 2.0, który zakodował tylko 16-bitowe punkty kodowe.) Ponadto Java nie używa UTF-16, używa zmodyfikowanej formy, w której kod wskazuje 0 jest zakodowane inaczej.
rdb
@rdb - Przeciwnie. Odpowiedź mówi, że UTF-16 reprezentuje BMP.
Nicolas Barbulesco
3
Pomyliłem się; Chciałem powiedzieć „non-BMP”. Błąd w odpowiedzi polega na tym, że mówi, że UTF-16 reprezentuje znaki BMP, co jest niedokładne. UTF-16 może kodować wszystkie znaki Unicode - znaki inne niż BMP są kodowane za pomocą par zastępczych. Być może odpowiadający był mylony z UCS-2.
rdb
17

W UTF-8:

1 byte:       0 -     7F     (ASCII)
2 bytes:     80 -    7FF     (all European plus some Middle Eastern)
3 bytes:    800 -   FFFF     (multilingual plane incl. the top 1792 and private-use)
4 bytes:  10000 - 10FFFF

W UTF-16:

2 bytes:      0 -   D7FF     (multilingual plane except the top 1792 and private-use )
4 bytes:   D800 - 10FFFF

W UTF-32:

4 bytes:      0 - 10FFFF

10FFFF jest ostatnim kodem Unicode z definicji i jest zdefiniowany w ten sposób, ponieważ jest to limit techniczny UTF-16.

Jest to również największy punkt kodowy UTF-8, który może kodować w 4 bajtach, ale idea kodowania UTF-8 działa również w przypadku kodowania 5 i 6 bajtów, aby pokryć punkty kodowe do 7FFFFFFF, tj. połowa tego, co potrafi UTF-32.

Jan
źródło
8

W Unicode odpowiedź nie jest łatwa. Problem, jak już wskazałeś, polega na kodowaniu.

Biorąc pod uwagę dowolne zdanie w języku angielskim bez znaków diakrytycznych, odpowiedź dla UTF-8 będzie miała tyle bajtów, ile znaków, a dla UTF-16 będzie to liczba znaków dwa razy.

Jedynym kodowaniem, w którym (na razie) możemy wypowiedzieć się na temat rozmiaru, jest UTF-32. Tam zawsze jest 32 bity na znak, chociaż wyobrażam sobie, że punkty kodowe są przygotowane na przyszły UTF-64 :)

To, co czyni to tak trudnym, to co najmniej dwie rzeczy:

  1. skomponowane znaki, w których zamiast używać encji znakowej, która jest już akcentowana / diakrytyczna (À), użytkownik postanowił połączyć akcent i znak podstawowy (`A).
  2. punkty kodowe. Punkty kodowe to metoda, za pomocą której kodowanie UTF pozwala zakodować więcej niż liczba bitów, które nadaje im ich nazwa. Np. UTF-8 oznacza pewne bajty, które same w sobie są nieprawidłowe, ale po których następuje poprawny bajt kontynuacyjny pozwoli opisać znak poza 8-bitowym zakresem 0..255. Zobacz przykłady i długie kodowanie poniżej w artykule Wikipedii na temat UTF-8.
    • Podany tam doskonały przykład jest taki, że znak € (punkt kodowy U+20ACmoże być reprezentowany jako sekwencja trzy bajtowaE2 82 AC lub sekwencja czterobajtowaF0 82 82 AC .
    • Oba są poprawne, co pokazuje, jak skomplikowana jest odpowiedź, gdy mówimy o „Unicode”, a nie o konkretnym kodowaniu Unicode, takim jak UTF-8 lub UTF-16.
0xC0000022L
źródło
4

Cóż, właśnie podciągnąłem na nim stronę Wikipedii, aw części wstępnej zobaczyłem, że „Unicode może być implementowany za pomocą różnych kodowań znaków. Najczęściej stosowanymi kodowaniami są UTF-8 (który używa jednego bajtu dla dowolnych znaków ASCII, które mają te same wartości kodu zarówno w kodowaniu UTF-8, jak i ASCII oraz do czterech bajtów dla innych znaków, obecnie nieaktualny UCS-2 (który używa dwóch bajtów dla każdego znaku, ale nie może zakodować wszystkich znaków w bieżącym standardzie Unicode) ”

Jak pokazuje ten cytat, twoim problemem jest to, że zakładasz, że Unicode jest jednym ze sposobów kodowania znaków. W rzeczywistości istnieje wiele form Unicode, i znowu w tym cytacie, jeden z nich ma nawet 1 bajt na znak, tak jak przywykłeś.

Tak więc twoją prostą odpowiedzią jest to, że jest różna.

Loduwijk
źródło
3

W przypadku UTF-16 znak potrzebuje czterech bajtów (dwóch jednostek kodu), jeśli zaczyna się od 0xD800 lub większej; taka postać nazywa się „parą zastępczą”. Mówiąc dokładniej, para zastępcza ma postać:

[0xD800 - 0xDBFF]  [0xDC00 - 0xDFF]

gdzie [...] oznacza dwubajtową jednostkę kodu o podanym zakresie. Wszystko <= 0xD7FF to jedna jednostka kodu (dwa bajty). Wszystko> = 0xE000 jest nieprawidłowe (z wyjątkiem znaczników BOM, prawdopodobnie).

Zobacz http://unicodebook.readthedocs.io/unicode_encodings.html , sekcja 7.5.

prewett
źródło
1

Z Wiki:

UTF-8, 8-bitowe kodowanie o zmiennej szerokości, które maksymalizuje kompatybilność z ASCII;

UTF-16, 16-bitowe kodowanie o zmiennej szerokości;

UTF-32, 32-bitowe kodowanie o stałej szerokości.

Są to trzy najpopularniejsze różne kodowania.

  • W UTF-8 każdy znak jest zakodowany w 1 do 4 bajtów (kodowanie dominujące)
  • W UTF16 każdy znak jest zakodowany w 1 do dwóch 16-bitowych słowach i
  • w UTF-32 każdy znak jest zakodowany jako pojedyncze 32-bitowe słowo.
chikityna
źródło
1

Unicodeto standard, który zapewnia unikalny numer dla każdej postaci. Te unikalne numery są nazywanecode point s (co jest po prostu unikalnym kodem) dla wszystkich znaków istniejących na świecie (niektóre z nich są jeszcze do dodania).

Do różnych celów może być konieczne przedstawienie tego code pointsw bajtach (większość języków programowania to robi), a oto gdzie Character Encodingzaczyna.

UTF-8, UTF-16, UTF-32I tak dalej, to wszystko Character Encodings, a punkty kodowe Unicode są reprezentowane w tych kodowań, na różne sposoby.


UTF-8 kodowanie ma zmienną szerokość, a zakodowane w nim znaki mogą zajmować od 1 do 4 bajtów włącznie;

UTF-16ma zmienną długość, a zakodowane w nim znaki mogą zająć 1 lub 2 bajty (czyli 8 lub 16 bitów). Reprezentuje to tylko część wszystkich znaków Unicode o nazwie BMP (Basic Multilingual Plane) i wystarcza na prawie wszystkie przypadki. Java używa UTF-16kodowania dla swoich ciągów znaków i znaków;

UTF-32 ma ustaloną długość, a każdy znak zajmuje dokładnie 4 bajty (32 bity).

Giorgi Tsiklauri
źródło