ASCII и ANSI
През 60-те години на XX век липсва общ стандарт за кодиране на символи и всеки производител на хардуер използва собствени кодове за символите.
Боб Бъмър – програмист в IBM, наричан „бащата на ASCII“ – обръща внимание, че с използването на различни стандарти, машините на IBM не могат да комуникират помежду си, а още по-малко с машините на останали производители. През май 1961 г. той предлага на Американския институт за стандартизация да се въведе и използва общ стандарт между компютрите. За работа по проекта се създава подкомитет X3.2, съставен от представители на повечето производители на компютри. Всеки от производителите настоява да запази своя начин на представяне на символите. Повече от две години са нужни на комитета, за да постигнат съгласие за един общ код.
ASCII е 7-битов код (character encoding), което означава, че може да представи 128 символа, 33 от които – непечатаеми (които служат за управление на устройства за обработка на текст) и съдържа само латински букви, арабски цифри и някои специални символа като пункуационни такива и т.н…
ASCII определя еднозначно съответствие между двоични кодове и писмени знаци (глифи), правейки възможна обмяната на текстова информация между отделни цифрови устройства, както и нейното съхраняване в тези устройства. Важно е да се отбележи, че ASCII определя съответствие между кода и семантичната стойност на глифа, а не негова конкретна визуална реализация (тоест, как точно изглежда дадената буква, цифра или друг знак).
Компютърните шрифтове определят визуалната реализациите на глифите. Тоест, ASCII няма нищо общо с това как точно, с какъв шрифт, даденият символ ще бъде изобразен.
Да вземем за пример главната латинска буква A – нейният двоичен код е 0100 0001, което е 65 в десетичен код или 41 в шестнайсетичен. В един обикновен текстов файл в ASCII код тя ще бъде представена именно с този код – 65(10) или 41(16). Но за да се изобрази на екрана, е нужен шрифт, който от своя страна съпоставя на този код някакво изображение. Това изображение е различно при отделните шрифтове, но смисълът му е един и същ – главна латинска буква A.
ANSI
Когато, с времето възниква нужда от покриване на повече писмени знаци (глифи), ASCII прераства в ANSI чрез добавяне на още един бит – старши бит, от ляво.
Това удвоява броя на възможните символи, тоест ако до тогава в ASCII кодът с най-голяма числова стойностт е бил:
0111 1111 демек 127(10)
сега вече щом ще използваме и най-старшият бит от този байт, ще започнем от:
1000 0000 демек 128(10)
и т.н… до
1111 1111 демек 255(10)
Това открива възможността да можем да удвоим броя възможни символни кода, които да съхраним.
Досегашните 128 символа от ASCII си остават, просто ги допълваме с още толкова.
Което е половината новина, другата половина е, че всеки има различни идеи кои точно да са тези допълнителни символи. Така възникват т.н. „code pages“ – това са тези различни, отделни „допълнения“ от по 128 символа.
Тези различни code pages най-често са на национален принцип, демек – имат цел да покрият даден език или по-скоро азбука – гръцки, еврейски, кирилица…
Просто казано, всички code pages си приличат само в първата половина. От там нататък… всичко е специфично за дадената code page.
In the ANSI standard, everybody agreed on what to do below 128, which was pretty much the same as ASCII, but there were lots of different ways to handle the characters from 128 and on up, depending on where you lived. These different systems were called code pages.
The main difference between ANSI and ASCII is the number of characters they can represent. ASCII was the first to be developed and when its limitations were reached, ANSI was one of the ways created to expand the number of characters that can be represented in an encoding, increasing the maximum number of characters to be represented up to 256. ASCII just defines a 7 bit code page with 128 symbols. ANSI extends this to 8 bit and there are several different code pages for the symbols 128 to 255.
Eто от този пример: https://en.wikipedia.org/wiki/Windows-1252 се вижда ясно как от този конкретен codepage (Windows-1252), ASCII таблицата е само първата половина, след това започват конкретните за него Windows-1252 codepage.
За друг codepage имаме подобна картина:
https://en.wikipedia.org/wiki/Code_page_932_(Microsoft_Windows)
Изводът е, че всеки codepage сам за себе си дефинира кои ще са символите, с кодове по-големи от 127 (10), стига само кодовете от 0 до 127 да са за същите символи като на ASCII.
Добър въпрос би бил, ОК имаме даден текстов файл или дадена web страница, кодирана в даден codepage. Kaк да знаем кой е codepage и за да я визуализираме?
До колкото знам, файловете в хедърите си имат такава информация.
За web страниците – там имаме специален HTTP header
Content-Type: text/html; charset=UTF-8
както и HTML мета таг.
Друго просто и важно е да се знае, че няма такъв eнкодинг наречен ANSI. ANSI e просто концепцията (даже по-скоро името на организацията) за това как да се удвои броя символни кода като се използва и най-старшият байт. За да кажеш, че даден файл например е кодиран с ANSI трябва да знаеш с коя конкретно code page е кодиран, защото всичко над 127(10) зависи от това.
Unicode
С времето и най-вече навлизането на Интернет, се вижда, че и 8 бита са крайно недостатъчни, защото има азбуки с хиляди букви (глифи). Така възниква Unicode.
Има един широко разпространен мит, че всеки Unicode символ е 16 битов код и следователно Unicode може да поддържа максимално 65,536 символа. Това не е точно така.
На всеки Unicode символ е зададен уникален т.н. „code point“ напр. U+0041 за латинско А. U+ значи Unicode, а двата байта след него са самият code point, който е шестнайсетично число. Няма лимит за броя символи, обхванати от Unicode, отделно, те отдавна са надхвърлили 65,536 броя.
Как обаче този code point се съхранява в паметта?
Да вземем стрингът Hello
В Unicode той е пет code points U+0048 U+0065 U+006C U+006C U+006F
Което в паметта е 00 48 00 65 00 6C 00 6C 00 6F
Ясно се виждат двойките байтове за всеки символ.
Meжду другото така е и била първоначалната идея за Unicode – всичко да е по два байта и толкоз. Явно оттам е тръгнал и митът, че в Unicode всеки символ е винаги точно 2 байта.
Тук също идва и едно понятие, наречено endianness или байтова подредба, според което понятие ако имаме little endian 00 48 ще е 48 00, ако имаме big endian ще си e 00 48. Което довело до нуждата предварително да се знае какъв е endianness-ът на даден стринг.
Измислили т.н. Unicode Byte Order Mark пред всеки стринг и можел да бъде или FE FF или FF FE, но това била неудачна идея.
Така или иначе, два байта си трябват, само че реално, в повечето случаи (напр. английски и други латински езици като латинско A) и един байт е напълно достатъчен.
„Много нули бре!“ скочили разни люде, и правилно, ако е за латински букви, си е загуба на един излишен байт за всяка. Пък и отделно, всичко написано до тогава на ASCII и ANSI как да се преправи на Unicode?
Изглеждало, че дните на Unicode са преброени.
И тук се родил UTF-8. При него, ако кодът на символа е между 0 и 127 (застъпване с доброто старо ASCII) използваме ЕДИН байт, не два. Явно това значи 8 в UTF-8, демек колко минимално памет може да се заделя за всеки символ.
Вече, за code points над 127 се заделят 2, 3, 4, 5 до 6 байта. Това е идеята на UTF-8 – да е по-пестелив откъм сторидж, демек, ако може един символ да се представи с 1 байт, да не се представя с 2.
Kоето също значи, че латинските знаци например съвпадат 1 към 1 с ASCII и ANSI събратята си.
И ето няколко начина за кодиране в Unicode:
- Традиционният, двубайтов начин, още познат като UCS-2 или UTF-16. Тук обаче е важен endianness, подредбата на байтовете. Демек може да имаме big endian UTF-16 (UCS-2) или little endian UTF-16 (UCS-2). Ако няма BOM се разбира по подразбиране big-endian.
- UTF-8
- UTF-7 – същото като UTF-8 но старшият бит на всеки байт трябва да е 0
https://bg.wikipedia.org/wiki/ASCII
http://ascii-table.com/codepage.php?1252
UTF-8 vs. UTF-16
UTF-8 and UTF-16 both handle the same Unicode characters. They are both variable length encodings that require up to 32 bits per character. The difference is that UTF-8 encodes the common characters including English and numbers using 8-bits. UTF-16 uses at least 16-bits for every character.
UTF-16 и UTF-32 са несъвместими с ASCII, за разлика от UTF-8.
UTF-8 requires 8, 16, 24 or 32 bits (one to four bytes) to encode a Unicode character, UTF-16 requires either 16 or 32 bits to encode a character, and UTF-32 always requires 32 bits to encode a character.
Литература:
https://simplicable.com/new/utf-8-vs-utf-16
https://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings