Dlaczego angielskie znaki wymagają mniejszej liczby bajtów do reprezentacji niż inne alfabety?

31

Kiedy wstawiam „a” w pliku tekstowym, robi to 2 bajty, ale kiedy wstawiam, powiedzmy „ա”, czyli literę alfabetu ormiańskiego, robi to 3 bajty.

Jaka jest różnica między alfabetami na komputerze?
Dlaczego angielski zajmuje mniej miejsca?

Khajvah
źródło
22
Powinieneś przeczytać ten artykuł założyciela StackExchange: joelonsoftware.com/articles/Unicode.html
Eric Lippert
22
Nie sądzę, że istnieje coś takiego jak „angielskie znaki”. Oni są Rzymianami.
Raphael
5
@ Rafael wszyscy wiedzą, o czym mówi. Ale fajnie dodaj.
Mathias Lykkegaard Lorenzen
1
@Raphael W rzeczywistości istnieje wiele liter rzymskich, które nie są używane w języku angielskim, a zatem nie są zawarte w zestawie znaków ASCII. Większość z nich zawiera modyfikatory, ale są one nadal potrzebne do poprawnego renderowania tekstu w różnych językach łacińskich innych niż angielski.
Wutaz
7
@ Rafael Nie sądzę, aby istniało coś takiego jak „postacie rzymskie”. Są łaciną.
Blacklight Shining

Odpowiedzi:

41

Jednym z pierwszych schematów kodowania, które zostaną opracowane do użytku w komputerach głównego nurtu, jest standard ASCII ( American Standard Code for Information Interchange ). Został opracowany w 1960 roku w Stanach Zjednoczonych.

Alfabet angielski używa części alfabetu łacińskiego (na przykład w języku angielskim jest kilka akcentowanych słów). Alfabet składa się z 26 pojedynczych liter, bez uwzględnienia wielkości liter. Musiałyby również istnieć pojedyncze cyfry i znaki interpunkcyjne na każdym schemacie, który udaje, że koduje alfabet angielski.

Lata sześćdziesiąte to także czas, w którym komputery nie miały tyle pamięci, ani miejsca na dysku, jakie mamy teraz. ASCII został opracowany jako standardowa reprezentacja funkcjonalnego alfabetu na wszystkich komputerach amerykańskich. Wówczas decyzja o tym, aby każdy znak ASCII miał długość 8 bitów (1 bajt), została podjęta ze względu na techniczne szczegóły tego czasu (artykuł w Wikipedii wspomina o tym, że perforowana taśma utrzymywała 8 bitów na raz). W rzeczywistości oryginalny schemat ASCII może być przesyłany przy użyciu 7 bitów, a osiem można wykorzystać do kontroli parzystości. Późniejsze zmiany rozszerzyły oryginalny schemat ASCII o kilka znaków akcentowanych, matematycznych i terminalnych.

W związku z ostatnim wzrostem korzystania z komputera na całym świecie coraz więcej osób z różnych języków miało dostęp do komputera. Oznaczało to, że dla każdego języka należało opracować nowe schematy kodowania, niezależnie od innych schematów, które byłyby sprzeczne, gdyby były czytane z różnych terminali językowych.

Unicode powstał jako rozwiązanie istnienia różnych terminali, łącząc wszystkie możliwe znaczące znaki w jeden abstrakcyjny zestaw znaków.

UTF-8 to jeden ze sposobów kodowania zestawu znaków Unicode. Jest to kodowanie o zmiennej szerokości (np. Różne znaki mogą mieć różne rozmiary) i zostało zaprojektowane z myślą o kompatybilności wstecznej z poprzednim schematem ASCII. Jako taki, zestaw znaków ASCII pozostanie duży na jeden bajt, podczas gdy inne znaki będą miały dwa lub więcej bajtów. UTF-16 to kolejny sposób kodowania zestawu znaków Unicode. W porównaniu do UTF-8 znaki są kodowane jako zestaw jednej lub dwóch 16-bitowych jednostek kodu.

Jak stwierdzono w komentarzach, znak „a” zajmuje jeden bajt, podczas gdy „ա” zajmuje dwa bajty, co oznacza kodowanie UTF-8. Dodatkowy bajt w twoim pytaniu wynikał z istnienia znaku nowej linii na końcu (o którym dowiedział się PO).

Doktoro Reichard
źródło
26
Nie ma ostatniego bajtu, który koduje koniec pliku, w dowolnym normalnym kodowaniu lub formacie pliku. Gdy program czyta plik, system operacyjny może sygnalizować koniec pliku w specjalny sposób, ale to inna sprawa.
Jukka K. Korpela,
2
Znak is ma 2 bajty (0xD5A1) w wersji UTF-8 Unicode; dodatkowy znak (cokolwiek to jest) jest obecny w obu plikach. marathon-studios.com/unicode/U0561/Armenian_Small_Letter_Ayb
Dan Neely
6
@khajvah Jeśli echo 'ա' > file.txtto zrobisz lub edytujesz plik za pomocą edytorów, automatycznie dodają po nim nowy wiersz. Jeśli uruchomisz xxd file.txt, ostatnim bajtem będzie prawdopodobnie 0alinia lub wiersz.
Daniel Beck
7
@DoktoroReichard: Proszę wyjaśnić w odpowiedzi, że Unicode nie jest kodowaniem; jest to raczej abstrakcyjny zestaw znaków, a UTF-16 i UTF-8 są kodowaniem punktów kodowych Unicode. Ostatnie akapity twojej odpowiedzi mówią głównie o UTF-8. Ale jeśli plik używa UTF-16, to każdy punkt kodowy, nawet ten dla a, użyje dwóch bajtów (lub wielokrotności dwóch).
grawitacja
6
Warto też chyba podkreślić, że „rozszerzone zestawy znaków ASCII” w rzeczywistości wcale nie są ASCII, a liczba różnych sposobów wykorzystania ósmego bitu sprawia, że ​​jest to wielki bałagan. Zamiast tego użyj UTF-8.
ntoskrnl
17

1 bajt to 8 bitów, a zatem może reprezentować do 256 (2 ^ 8) różnych wartości.

W przypadku języków, które wymagają więcej możliwości, proste mapowanie 1 do 1 nie może być utrzymane, więc potrzeba więcej danych do przechowywania znaku.

Zauważ, że ogólnie większość kodowań używa pierwszych 7 bitów (128 wartości) dla znaków ASCII . Pozostawia to 8-ty bit lub 128 więcej wartości dla większej liczby znaków. . . dodaj znaki akcentowane, języki azjatyckie, cyrylicę itp., aby łatwo zrozumieć, dlaczego 1 bajt nie wystarcza do zachowania wszystkich znaków.

ernie
źródło
oto więc jedyna odpowiedź, która wyjaśnia, dlaczego wykorzystuje się więcej miejsca
Félix Gagnon-Grenier
10

W UTF-8 znaki ASCII używają jednego bajtu, inne znaki używają dwóch, trzech lub czterech bajtów.

Jason
źródło
1
Czy możesz wyjaśnić, dlaczego tak jest? zauważenie dwóch metod kodowania nie do końca odpowiada na pytanie.
MaQleod
@MaQleod Unicode został utworzony w celu zastąpienia ASCII. Dla kompatybilności wstecznej pierwsze 128 znaków jest takich samych. Te 128 znaków można wyrazić jednym bajtem. Dodatkowe bajty są dodawane dla dodatkowych znaków.
Jason
Wiem, ale to część odpowiedzi na pytanie, co odróżnia znaki ASCII. Należy to wyjaśnić PO.
MaQleod,
@MaQleod Można również powiedzieć, że konsorcjum Unicode składało się głównie z korporacji amerykańskich i było stronnicze w stosunku do znaków w języku angielskim. Myślałem, że prosta odpowiedź była lepsza niż subiektywna.
Jason
15
Nie „w Unicode”, w UTF8 - który jest tylko jednym z kilku kodowań zestawu znaków Unicode.
Sebastian Negraszus
3

Ilość bajtów wymagana dla znaku (o którym najwyraźniej chodzi o pytanie) zależy od kodowania znaku. Jeśli używasz kodowania ArmSCII, każda litera armeńska zajmuje tylko jeden bajt. Jednak w dzisiejszych czasach nie jest to dobry wybór.

W kodowaniu przesyłania UTF-8 dla Unicode znaki wymagają innej liczby bajtów. W nim „a” zajmuje tylko jeden bajt (idea dwóch bajtów jest pewnego rodzaju zamieszaniem), „á” zajmuje dwa bajty, a ormiańska litera ayb „ա” również zajmuje dwa bajty. Trzy bajty muszą być pewnego rodzaju zamieszaniem. Dla kontrastu, np. Litera bengalska „অ” zajmuje trzy bajty w UTF-8.

Tłem jest po prostu to, że UTF-8 został zaprojektowany tak, aby był bardzo wydajny dla znaków Ascii, dość wydajny dla systemów pisania w Europie i otoczeniu, a cała reszta jest mniej wydajna. Oznacza to, że podstawowe litery łacińskie (z których w większości składa się tekst angielski), potrzebny jest tylko jeden bajt dla znaku; w przypadku greckiego, cyrylicy, ormiański i kilku innych potrzebne są dwa bajty; cała reszta potrzebuje więcej.

UTF-8 ma (jak wskazano w komentarzu) także użyteczną właściwość, że dane Ascii (reprezentowane jako jednostki 8-bitowe, co było prawie jedynym sposobem od dłuższego czasu), są również w prosty sposób zakodowane w UTF-8.

Jukka K. Korpela
źródło
Dziękuję za Twoją odpowiedź. Dodatkowe bajty są spowodowane tym, że program, którego użyłem, automatycznie dodał na końcu znak nowej linii.
khajvah
1
Nie sądzę, aby UTF-8 był tak zaprojektowany pod kątem wydajności z danymi ASCII, jak pod względem kompatybilności . UTF-8 ma bardzo dobrą właściwość, że 7-bitowa zawartość ASCII (z wysokim bitem ustawionym na zero) jest identyczna z tą samą zawartością zakodowaną jak UTF-8, więc w przypadku narzędzi, które normalnie radzą sobie z ASCII, jest to zamiennik drop-in . O ile mi wiadomo, żaden inny schemat kodowania Unicode nie ma tej właściwości. UTF-8 jest również dość kompaktowy dla większości danych, szczególnie jeśli pozostajesz w sferze Unicode BMP .
CVn
1
@ MichaelKjörling, dodałem odniesienie do tej funkcji. Jednak głównym sprzeciwem wobec Unicode na początku była nieefektywność, a UTF-16 podwaja rozmiar danych, które są głównie Ascii. UTF-8 oznacza, np. W przypadku tekstu angielskiego, że „płacisz” tylko za znaki, których nie używasz w języku Ascii.
Jukka K. Korpela
3

Kody znaków w latach 60. XX wieku (i znacznie później) były specyficzne dla maszyny. W latach 80. krótko użyłem maszyny DEC 2020, która miała 36 bitów słów oraz 5, 6 i 8 bitów ( IIRC ) na kodowanie znaków. Wcześniej korzystałem z serii IBM 370 z EBCDIC. ASCII z 7 bitami uporządkował, ale dostał bałagan z „stronami kodowymi” IBM PC, używając wszystkich 8 bitów do przedstawienia dodatkowych znaków, takich jak wszelkiego rodzaju rysunki pudełkowe do malowania prymitywnych menu, a później rozszerzenia ASCII, takie jak Latin-1 (8 bitów) kodowania, przy czym pierwsze 7 bitów jak ASCII, a druga połowa dla „bohaterów narodowych” takich ñ, Çczy innych. Prawdopodobnie najbardziej popularne było Latin-1, dostosowane do języka angielskiego i większości języków europejskich przy użyciu znaków łacińskich (i akcenty i warianty).

Pisanie mieszania tekstu, np. Angielskiego i hiszpańskiego, poszło dobrze (wystarczy użyć Latin-1, nadzbiór obu), ale mieszanie wszystkiego, co używało innego kodowania (np. Fragment greckiego lub rosyjskiego, nie mówiąc już o języku azjatyckim, takim jak japoński) było istny koszmar. Najgorsze było to, że rosyjski, a zwłaszcza japoński i chiński, miał kilka popularnych, całkowicie niekompatybilnych kodowań.

Dziś używamy Unicode, który jest spakowany do wydajnych kodowań, takich jak UTF-8, które faworyzują znaki angielskie (co zaskakujące, kodowanie liter angielskich tak się składa, że ​​odpowiada ASCII), przez co wiele znaków nieanglojęzycznych używa dłuższych kodowań.

vonbrand
źródło
2

Plik Windows 8.1 US / angielski z pojedynczym „a” zapisanym za pomocą notatnika.

  • Zapisz AS 1 bajt ANSI
  • Zaoszczędź 4 bajty jako Unicode
  • Zapisz jako 4 bajty UTF-8

Plik z pojedynczym „ա” zapisanym w notatniku

  • Zapisywanie AS ANSI nie jest możliwe
  • Zaoszczędź 4 bajty jako Unicode
  • Zaoszczędź 5 bajtów jako UTF-8

Pojedynczy „a” jest kodowany jako pojedynczy bajt w ANSI, w Unicode każdy znak ma zwykle 2 bajty, na początku pliku znajduje się również 2 bajtowy BOM (Bajt Marker). UTF-8 ma 3-bajtowe BOM i znak jednobajtowy.

Dla „ա” ten znak nie istnieje w zestawie znaków ANSI i nie można go zapisać na moim komputerze. Plik Unicode jest taki sam jak poprzednio, a plik UTF-8 jest o 1 bajt większy, ponieważ znak zajmuje 2 bajty.

Jeśli twoje urządzenie pochodzi z innego regionu, możesz mieć zainstalowaną inną stronę kodową OEM, która ma różne glify dla 255 możliwych znaków w zakresie ASCII. Jak wspomniałem @ntoskrnl, strona kodowa OEM dla mojego komputera to Windows-1252, który jest domyślnym językiem angielskim w USA.

Darryl Braaten
źródło
4
Notatnik (i ogólnie system Windows) używa tu mylącej terminologii. „ANSI” jest zależnym od regionu kodowaniem jednobajtowym (Windows-1252 w wersji angielskiej), a „Unicode” to UTF-16.
ntoskrnl
@ntoskrnl To prawda, ale jeśli szukasz w polu rozwijanym do kodowania, to mówi ANSI, dlatego wspomniałem, że jeśli masz inną stronę kodową OEM, możesz uzyskać różne wyniki.
Darryl Braaten
2

Jeśli interesuje Cię sposób przechowywania znaków, możesz przejść do www.unicode.org i rozejrzeć się. U góry strony głównej znajduje się link „Tabele kodów”, który pokazuje wszystkie kody znaków dostępne w standardzie Unicode.

Podsumowując, w Unicode dostępnych jest nieco ponad milion kodów (nie wszystkie są używane). Jeden bajt może pomieścić 256 różnych wartości, więc potrzebujesz trzech bajtów, jeśli chcesz zapisać każdy możliwy kod Unicode.

Zamiast tego Unicode jest zwykle przechowywany w kodowaniu „UTF-8”, który wykorzystuje mniej bajtów dla niektórych znaków i więcej dla innych. Pierwsze 128 wartości kodu jest przechowywanych w jednym bajcie, do pierwszych 2048 wartości kodu jest przechowywanych w dwóch bajtach, do 65536 jest przechowywanych w trzech bajtach, a pozostałe zajmują cztery bajty. Zostało to ustawione tak, aby częściej używane wartości kodu zajmowały mniej miejsca. AZ, az, 0-9 i! @ $% ^ & * () - [} {}; ': "|,. / <>? I niektóre, o których zapomniałem, zajęły jeden bajt; prawie cały angielski, 98% Niemiecki i francuski (tylko zgadywanie) mogą być przechowywane w jednym bajcie na znak, a są to znaki, które są najczęściej używane. Cyrylica, grecki, hebrajski, arabski i niektóre inne używają dwóch bajtów na znak. Języki indyjskie, większość chińska, japońska , Koreański, tajski, mnóstwo symboli matematycznych, można zapisać w trzech bajtach na znak. Rzadkie rzeczy (jeśli kiedykolwiek chcesz pisać tekst w Linear A lub Linear B, Emoji) zajmują cztery bajty.

Kolejnym kodowaniem jest UTF-16. Wszystko, co zajmuje 1, 2 lub 3 bajty w UTF-8, zajmuje dwa bajty w UTF-16. Jest to zaleta, jeśli masz tekst chiński lub japoński z niewielką liczbą znaków łacińskich.

O przyczynach projektu UTF-8: Ma kilka zalet w porównaniu z innymi projektami. Oni są:

Zgodność ze znakami US-ASCII

Rozsądna zwartość

Samosynchronizacja: Oznacza to, że jeśli otrzymasz część sekwencji bajtów, które są znakami w kodowaniu UTF-8, możesz dowiedzieć się, gdzie zaczyna się znak. W niektórych kodowaniach zarówno xy, jak i yx mogą być prawidłowymi kodowaniami znaków, więc jeśli otrzymasz część sekwencji ... xyxyxyxyxyxy ... nie możesz wiedzieć, jakie masz znaki.

Poprawność sortowania: Jeśli sortujesz ciągi zawierające znaki zakodowane w UTF-8 według ich wartości bajtów, są one automatycznie sortowane poprawnie zgodnie z ich wartościami Unicode.

Zgodny z kodem jednobajtowym: większość kodu, który zakłada wartości jednobajtowe, działa automatycznie poprawnie ze znakami zakodowanymi w UTF-8.

Plus niezależnie od powodów, o których zapomniałem.

gnasher729
źródło