Absolutne minimum, które każdy programista powinien koniecznie, absolutnie wiedzieć na temat Unikodu i zestawów znaków (bez wymówek!)

Oryginalny post: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Autor: Joel Spolsky

Czy kiedykolwiek zastanawiałeś się nad tajemniczym tagiem Content-Type? No wiesz, tym, który powinieneś umieścić w HTML-u i nigdy do końca nie wiesz, co powinien zawierać?

Czy kiedykolwiek dostałeś mejla od przyjaciół z Bułgarii z tematem "???? ?????? ??? ????"?

ibm Byłem przerażony, kiedy odkryłem, jak wielu programistów nie jest na bieżąco z tajemniczym światem zestawów znaków, kodowań, Unikodu, całego tego zamieszania. Kilka lat temu beta tester systemu FogBUGZ zastanawiał się, czy może on obsłużyć przychodzącego mejla w języku japońskim. "Japońskim? W Japonii mają mejla? Nie miałem pojęcia." Kiedy przyjrzałem się bliżej komercyjnej kontrolce ActiveX, której używaliśmy do parsowania wiadomości email w formacie MIME, odkryliśmy, że robiła wszystko źle, jeśli chodzi o obsługę zestawów znaków, więc musieliśmy napisać heroiczny wręcz kod, żeby odwrócić całą błędną konwersję, a następnie wykonać ją od nowa. Kiedy spojrzałem na inną komercyjną bibliotekę, ona także miała kompletnie spartaczoną implementację kodów znaków. Korespondowałem z programistą tego pakietu, ale on myślał coś w stylu "nic nie da się z tym zrobić". Jak wielu programistów po prostu chciał, żeby to wszystko jakoś zniknęło z czasem.

Ale to nie zniknie. Kiedy odkryłem, że popularne narzędzie do programowania aplikacji webowych - PHP wykazuje się prawie kompletną ignorancją w zakresie kodowania znaków, beztrosko używając ośmiu bitów na znak, czyniąc prawie niemożliwym tworzenie dobrych międzynarodowych aplikacji webowych, pomyślałem wystarczy.

A więc mam pewną rzecz do ogłoszenia: Jeśli jesteś programistą pracującym w roku 2003 i nie znasz podstaw znaków, zestawów znaków, kodowań, Unikodu i złapię Cię, ukarzę Cię, zmuszając do obierania cebuli przez 6 miesięcy w łodzi podwodnej. Obiecuję, że to zrobię.

I jeszcze jedna rzecz:

TO NIE JEST TAKIE TRUDNE.

W tym artykule dostarczę Ci informacji o tym, co każdy pracujący programista powinien wiedzieć. Cała ta gadka, że "czysty text = ascii = znaki mają po 8 bitów" jest nie tylko mylna, ale beznadziejnie mylna i jeśli nadal programujesz w ten sposób, nie jesteś lepszy od lekarza, który nie wierzy w bakterie. Proszę nie pisz nawet jednej linijki kodu więcej, dopóki nie przeczytasz do końca tego artykułu.

Zanim zacznę, powinienem Cię uprzedzić, że jeżeli jesteś jedną z tych niewielu osób, które wiedzą o internacjonalizacji, uznasz mój cały wywód za lekkie uproszczenie. Staram się tak naprawdę wyznaczyć minimum, które każdy będzie w stanie zrozumieć, a które pozwoli na pisanie kodu mającego szansę działać z tekstem w jakimkolwiek innym języku niż podzbiór angielskiego nie uwzględniający słów z akcentami. I powinienem uprzedzić Cię, że obsługa znaków to tylko mała część, która sprawia, że oprogramowanie działa w różnych językach. Jednak mogę pisać tylko o jednej rzeczy naraz, więc dzisiaj są to zestawy znaków.

Perspektywa historyczna

Najłatwiej zrozumieć to wszystko, idąc chronologicznie.

Prawdopodobnie myślisz, że będę teraz mówił o bardzo starych zestawach znaków takich jak EBCDIC. Hmm, nie będę. EBCDIC nie jest ważny w Twoim życiu. Nie musimy cofać się tak daleko w czasie.

ASCII table W pół-pradawnych czasach, kiedy wymyślano Unixa, a K&R pisali książkę Język ANSI C, wszystko było bardzo proste. EBCDIC miał właśnie ujrzeć światło dzienne. Jedynymi znakami, które się wtedy liczyły, były stare, dobre angielskie litery bez akcentów i mieliśmy dla nich kod nazywany ASCII, który był w stanie reprezentować każdy znak używając liczby między 32 a 127. Spacja miała numer 32, litera "A" - 65, itd. To pozwalało wygodnie zapisać znak na 7 bitach. Większość komputerów w tamtych czasach używało ośmio-bitowych bajtów, także nie tylko mogłeś zapisać każdy możliwy znak zestawu ASCII, ale miałeś cały wolny bit, który, jeśli byłeś złośliwy, mogłeś użyć dla swoich własnych, przebiegłych celów: tępacy w WordStar użyli najbardziej znaczącego bitu, żeby oznaczyć ostatnią literę w słowie, skazując WordStar wyłącznie na angielskie teksty. Kody poniżej 32 były nazywane niedrukowalnymi i używane były na przekleństwa. Ok, żartowałem. Były one używane do znaków kontrolnych, tak jak 7, które sprawiało, że komputer brzęczał, albo 12, które sprawiało, że strona papieru wylatywała z drukarki, aby nowa mogła zostać pobrana.

I wszystko było dobrze zakładając, że mówiłeś po angielsku.

oem Ponieważ bajt ma miejsce na maksymalnie 8 bitów, wielu ludzi zaczęło myśleć "boże, możemy użyć kodów 128-255 dla naszych potrzeb". Problem był w tym, że wielu ludzi wpadło na ten pomysł równocześnie i mieli swoje własne koncepcje na to, co powinno pojawić się w przestrzeni od 128 do 255. IBM-PC miał coś, co miało zostać zapamiętane jako zestaw znaków OEM zawierający litery z akcentami dla języków europejskich i trochę znaków rysujących linie... poziome bloki, pionowe bloki, poziome bloki z małymi dyndałkami dyndającymi z prawej strony itd., można było użyć tych znaków linii, żeby rysować fajniutkie pudełka i linie na ekranie, które można było obejrzeć na komputerach 8088 Twoich pralek chemicznych. Tak naprawdę, jak tylko ludzie zaczęli kupować PC-ty poza Ameryką, różne inne zestawy znaków OEM zaczynały być wymyślane, wszystkie używały ostatnich 128 znaków do swoich własnych potrzeb. Na przykład na niektórych PC-tach znak 130 mógł wyświetlić é, ale na komputerach sprzedawanych w Izraelu była to hebrajska litera Gimel (ג), więc gdy Amerykanie wysyłaliby swoje résumés do Izraela przeczytane zostałoby to jako rגsumגs. W wielu przypadkach, jak w przypadku Rosjan, było wiele różnych pomysłów, co zrobić z tymi górnymi 128 znakami, w rezultacie - nie mogłeś niezawodnie wymieniać dokumentów nawet w obrębie języka rosyjskiego.

W końcu ten OEM dostępny-dla-wszystkich został spisany w standard ANSI. W standardzie ANSI wszyscy zgodzili się co do znaków poniżej 128, co było w zasadzie tym samym, co w ASCII, ale było wiele różnych sposobów na obsługę znaków od 128 wzwyż, zależnie od tego, gdzie żyłeś. Te różne systemy były nazywane stronami kodowymi. Więc dla przykładu w Izraelu DOS używał strony kodowej nazywanej 862, w czasie gdy użytkownicy greccy używali 737. Były one takie same poniżej znaku 128, ale różne od 128 wzwyż, gdzie mieszkały wszystkie śmieszne literki. Wersje narodowe MS-DOSa miały tuziny stron kodowych, obsługujących wszystko od angielskiego po islandzki i miały nawet kilka "wielo-językowych" stron kodowych, które rozumiały Esperanto i Galicyjski na jednym komputerze! Wow! Ale posiadanie, powiedzmy, hebrajskiego i greckiego na jednej maszynie było kompletnie niemożliwe, dopóki nie napisałeś własnego programu, który wyświetlał wszystko używając bitmap, ponieważ hebrajski i grecki wymagają różnych stron kodowych z różną interpretacją wyższych numerów.

W tym samym czasie w Azji wymyślano jeszcze bardziej szalone rzeczy, aby uwzględnić fakt, że azjatycki alfabet zawiera tysiące liter, które nigdy nie zmieściłyby się na 8 bitach. To było zazwyczaj rozwiązywane przez koszmarny system DBCS, tak zwany "dwu-bajtowy zestaw znaków", w którym niektóre litery były przechowywane na jednym bajcie, a niektóre na dwóch. Było dość łatwo przeszukiwać łańcuch znaków wprzód, ale prawie niemożliwe przeszukiwać wstecz. Programiści byli zmuszeni nie używać s++ i s--, aby poruszać się wprzód i w tył, a zamiast tego musieli używać funkcji, takich jak AnsiNext i AnsiPrev w Windows'ie, które wiedziały, jak poradzić sobie z tym bałaganem.

Ale ciągle większość ludzi udawało, że bajt to jeden znak, a znak ma 8 bitów i tak długo, jak nie przenosili łańcuchów znaków z jednego komputera na inny albo nie mówili więcej niż jednym językiem, jakoś to niby zawsze działało. Ale oczywiście jak tylko pojawił się Internet, stał się on raczej popularnym miejscem do przesyłania łańcuchów znaków z jednego komputera na inny i cały ten bałagan zaczął się powoli walić. Na szczęście - wymyślono Unikod.

Unikod

Unikod był odważną próbą stworzenia jednego zestawu znaków, który zawierałby każdy rozsądny system piśmienniczy z całej planety, a także kilka egzotycznych jak klingoński. Niektórzy mylnie uważają, że Unikod to to po prostu kod 16-bitowy, w którym każdy znak zajmuje 16 bitów i dzięki temu można zapisać maksymalnie 65536 znaków. Właściwie - to nie jest prawda. To jest najbardziej popularny mit na temat Unikodu, więc jeśli tak właśnie myślałeś - nie martw się.

Unikod ma tak naprawdę inny sposób myślenia o znakach i musisz zrozumieć ten sposób myślenia Unikodu o rzeczach albo nic nie będzie później zrozumiałe.

Do tej pory zakładaliśmy, że litery są mapowane na kilka bitów, które przechowujemy na dysku lub w pamięci:

A -> 0100 0001

W Unikodzie litera jest mapowana na coś, co nazywa się punktem kodowym, który jest koncepcją czysto teoretyczną. Sposób, w jaki punkt kodowy jest reprezentowany w pamięci lub na dysku, jest inną bajką.

W Unikodzie litera A to koncepcja platoniczna. To bujający w obłokach twór:

A

To platoniczne A jest różne od B i różne od a, ale takie samo jak A i A a także A. Koncepcja, że A w czcionce Times New Roman to ten sam znak, co A w czcionce Helvetica, ale inny niż "a" z małej litery nie jest bardzo kontrowersyjne, ale w niektórych językach określenie czym jest litera może powodować kontrowersje. Czy niemiecka litera ß to naprawdę litera, czy tylko bardziej wydumany sposób napisania ss? Gdy kształt litery zmienia się na końcu słowa, czy jest to inna litera? Hebrajczycy powiedzą "tak", Arabowie - "nie". W każdym razie mądrzy ludzi w konsorcjum Unikodu zastanawiali się nad tym przez ostatnią dekadę lub dłużej, wspierani przez wiele wysoko-politycznych debat i nie musisz się już o te rzeczy martwić. Oni już to wszystko rozpracowali.

Każda platoniczna litera w każdym alfabecie jest przez konsorcjum Unikodu przypisana do magicznego numeru, który pisze się tak: U+0639.  Ten magiczny numer nazywa się punktem kodowym. U+ oznacza "Unikod" a następujące po nim liczby są zapisywane w systemie szesnastkowym. U+0639 to arabska litera Ain. Angielska litera A wyglądałaby tak: U+0041. Możesz je wszystkie odnaleźć, używając programu tablica znaków na Windows'ie 2000/XP albo odwiedzając stronę Unikodu.

Nie ma tak naprawdę limitu na liczbę liter, które może zdefiniować Unikod i w rzeczywistości ilość przekroczyła już 65536, więc nie każda litera w Unikodzie może być wciśnięta w dwa bajty, ale to był tak czy siak mit.

OK, więc mamy łańcuch znaków:

Hello

który, w Unikodzie, odpowiada tym pięciu punktom kodowym:

U+0048 U+0065 U+006C U+006C U+006F.

Po prostu kilka punktów kodowych. Liczb, tak naprawdę. Nie powiedzieliśmy jeszcze, jak przechowywać je w pamięci albo jak reprezentować w wiadomości email.

Kodowania

To właśnie miejsce, w którym kodowania wchodzą do gry.

Najwcześniejsza idea kodowania Unikodu, która doprowadziła do mitu na temat dwóch bajtów, to "hej, zapiszmy po prostu te liczby na dwóch bajtach każdą". Tak więc "Hello" stało się

00 48 00 65 00 6C 00 6C 00 6F

Racja? Nie tak szybko! Nie mogłoby to być równie dobrze:

48 00 65 00 6C 00 6C 00 6F 00 ?

Z technicznego punktu widzenia, mógłbym uwierzyć, że mogłoby. W zasadzie najwcześniejsze implementacje wręcz chciały zapisywać punkty kodowe Unikodu w notacji high-endian lub low-endian w zależności od tego, w której z nich szybszy był konkretny procesor, i nim ktokolwiek zdążył zauważyć, już istniały dwa sposoby na zapisanie Unikodu. A ludzie byli zmuszeni wymyślić dziwną konwencję dopisywania FE FF na początku każdego łańcucha znaków w Unikodzie; to tak zwany Znacznik Kolejności Bitów Unikodu i jeśli zamieniasz swoje wyższe i niższe bajty, to wygląda to tak: FF FE a ludzie czytający Twoje łańcuchy znaków będą wiedzieli, jak zamienić każdy następny bajt. Uff. Jednak nie każdy unikodowy łańcuch znaków występujący w przyrodzie ma znacznik kolejności bajtów na początku.

Hummers

Przez chwilę wydawało się, że to będzie wystarczające, ale programiści narzekali. "Popatrz na te wszystkie zera!" mówili, w końcu byli Amerykanami i patrzyli na angielskie teksty, które rzadko używały punktów kodowych ponad U+00FF. Ponadto byli oni liberalnymi hipisami z Kalifornii, którzy chcieli zachować stary porządek (hihi). Gdyby byli z Teksasu, nie mieli by nic przeciwko pożeraniu dwukrotnej ilości bajtów. Ale te kalifornijskie mięczaki nie mogły znieść podwajania ilości miejsca na łańcuchy znaków, a poza tym istniało wtedy tak dużo tych cholernych dokumentów w różnych odmianach ANSI i DBCS i kto je teraz przekonwertuje? Ja? Przez to większość ludzi ignorowało Unikod przez parę lat, a w międzyczasie wszystko się jeszcze bardziej pogarszało.

Dlatego wymyślono świetną rzecz - UTF-8. UTF-8 był kolejnym systemem przechowywania łańcuchów punktów kodowych Unikodu, tych magicznych numerów U+, w pamięci za pomocą 8-bitowych bajtów. W UTF-8 każdy punkt kodowy z przedziału 0-127 jest zapisywany na pojedynczym bajcie. Tylko punkty 128 i wyżej przechowywane są używając 2, 3 aż do 6 bajtów.

How UTF-8 works

To ma ten elegancki efekt uboczny, że angielskie teksty wyglądają tak samo w UTF-8, jak wyglądały w ASCII, więc Amerykanie nie widzą w tym nic złego. Tylko reszta świata musi się namęczyć. Konkretnie, Hello, które zapisywane było jako U+0048 U+0065 U+006C U+006C U+006F będzie zapisywane jako 48 65 6C 6C 6F, które, zaraz! wygląda tak samo jak w ASCII, w ANSI i w każdym zestawie znaków OEM na całej planecie. A jeśli jesteś na tyle głupi, żeby używać liter z akcentami, liter greckich lub klingońskich, musisz używać kilku bajtów, żeby zapisać pojedynczy punkt kodowy, ale Amerykanie nigdy tego nie zauważą. (UTF-8 ma także tę miłą właściwość, że ignorancki, stary kod przetwarzający łańcuchy znaków używający pojedynczego bajtu 0 jako oznaczenie wartości pustej, nie będzie ścinał łańcuchów znaków).

Póki co opowiedziałem o trzech sposobach kodowania Unikodu. Tradycyjna metoda zapisz-to-na-dwóch-bajtach nazywana jest UCS-2 (ponieważ ma dwa bajty) albo UTF-16 (ponieważ ma 16 bitów), ale musisz wiedzieć, jak rozróżnić UCS-2 z notacją high-endian albo low-endian. No i jest nowy, popularny standard UTF-8, który ma ciekawe właściwości i działa nieźle, jeśli masz do czynienia z tekstem angielskim i upośledzonymi umysłowo programami, które są kompletnie nieświadome świata poza ASCII.

Tak naprawdę istnieje wiele innych metod kodowania Unikodu. Jest coś, co nazywa się UTF-7, który jest bardzo podobny do UTF-8, ale gwarantuje, że najbardziej znaczący bit będzie zawsze zerem, więc gdy przesyłasz Unikod przez jakiś drakoński program pocztowy, który uważa, że 7 bitów to wystarczająco dużo, dziękuję bardzo, to nadal znaki mogą przecisnąć się niezniszczone. Jest UCS-4, który przechowuje punkt kodowy na 4 bajtach, co ma tę dobrą właściwość, że każdy pojedynczy punkt kodowy może być przechowywany na takiej samej liczbie bajtów, ale, o rany, nawet Teksańczycy nie byliby tak beztroscy, żeby marnować taką ilość pamięci.

No i teraz skoro już myślisz w kategoriach platonicznych, idealnych liter, które są reprezentowane za pomocą punktów kodowych Unikodu, to te unikodowe punkty kodowe mogą być zakodowane także w każdym z tradycyjnych schematów kodowych! Na przykład, mógłbyś zakodować łańcuch znaków Unikodu dla wyrazu Hello (U+0048 U+0065 U+006C U+006C U+006F) w ASCII albo kodowaniu greckim OEM albo hebrajskim kodowaniu ANSI albo w jednym z kilku setek kodowań, które zostały dotychczas wymyślone, ale z jednym haczykiem: niektóre litery mogą się nie pojawić! Jeśli nie ma żadnego odpowiednika dla unikodowego punktu kodowego, który starasz się przedstawić w konkretnym kodowaniu, zazwyczaj dostaniesz znak zapytania: ? albo jeśli jesteś naprawdę dobry - pudełko. Który znak dostałeś? -> �

Istnieją setki tradycyjnych kodowań, które potrafią przechowywać tylko niektóre punkty kodowe poprawnie, a wszystkie inne punkty kodowe zamieniają w znaki zapytania. Niektóre popularne kodowania angielskiego to Windows-1252 (standard Windows 9x dla języków zachodnio-europejskich) i ISO-8859-1, inaczej Latin-1 (także użyteczny dla każdego z zachodnio-europejskich języków). Ale próbując zapisać rosyjskie albo hebrajskie litery w tych kodowaniach dostaniemy tylko znaki zapytania. UTF 7, 8, 16, i 32 mają tę fajną właściwość, że potrafią zapisać jakikolwiek punkt kodowy poprawnie.

Najważniejsza prawda na temat kodowań

Jeśli kompletnie zapomnisz wszystko, co właśnie tłumaczyłem, proszę zapamiętaj tylko jedną, ekstremalnie ważną rzecz. Nie ma sensu mieć łańcucha znaków bez wiedzy, jakiego kodowania używa. Nie możesz dłużej chować głowy w piasek i udawać, że "czysty" tekst to ASCII.

Nie istnieje coś takiego, jak Czysty Tekst.

Jeśli masz łańcuch znaków, w pamięci, w pliku albo w wiadomości email, musisz wiedzieć jakiego używa kodowania albo nie jesteś w stanie go zinterpretować i wyświetlić użytkownikom prawidłowo.

Prawie każdy problem typu "moja strona internetowa wygląda jak bełkot" albo "ona nie może przeczytać mojego mejla, kiedy używam akcentów" sprowadza się do jednego naiwnego programisty, który nie zrozumiał prostego faktu, że jeśli nie powiesz wyraźnie, czy dany łańcuch znaków zakodowany jest w UTF-8, ASCII, ISO 8859-1 (Latin 1) albo Windows 1252 (Zachodnio-Europejski), nie można przedstawić tego łańcucha prawidłowo ani nawet powiedzieć, gdzie się kończy. Istnieje ponad setka kodowań, a powyżej punktu kodowego 127 - wszystko może się wydarzyć.

Jak przechowujemy tę informację o tym, jakiego kodowania używa łańcuch znaków? Hmm, są na to standardowe sposoby. Dla wiadomości email powinieneś mieć łańcuch znaków tego typu w nagłówku wiadomości

Content-Type: text/plain; charset="UTF-8"

Dla strony internetowej pomysł był taki, że serwer webowy zwróci podobną informację Content-Type w nagłówku http razem z zawartością strony -- nie w samym HTMLu, ale w jednym z nagłówków odpowiedzi na żądanie, które są wysyłane przed stroną HTML. 

To powoduje problemy. Przypuśćmy, że mamy wielki serwer webowy z wieloma pod-serwisami i setkami stron dodawanymi przez masę ludzi mówiących wieloma różnymi językami i używających różnego kodowania, które akurat wymyśliła im ich kopia Microsoft FrontPage'a. Sam serwer webowy nie za bardzo wie z jakim kodowaniem napisany był poszczególny plik, dlatego nie mógłby wysłać nagłówka Content-Type.

Byłoby całkiem wygodnie umieścić Content-Type dla danego pliku HTML w tym właśnie pliku, używając jakiegoś specjalnego znacznika. Oczywiście to doprowadza purystów do szaleństwa... jak w takim razie czytałbyś ten plik HTML, dopóki nie wiedziałbyś w jakim jest zapisany kodowaniu?! Na szczęście, niemal każde dostępne kodowanie tak samo traktuje znaki między 32 i 127, dlatego zawsze możesz dojść przynajmniej do tego miejsca na stronie HTML bez używania śmiesznych literek:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Ale ten znacznik meta powinien być naprawdę pierwszą rzeczą w sekcji <head>, ponieważ jak tylko przeglądarka internetowa zobaczy ten tag, przestanie parsować stronę i zacznie ponownie, interpretując wszystko w kodowaniu, które wyspecyfikowałeś.

Co robią przeglądarki internetowe, jeśli nie znajdą żadnego Content-Type ani w nagłówku http, ani w tagu meta? Internet Explorer robi rzecz ciekawą: próbuje zgadnąć, bazując na częstotliwości używania różnych bajtów w typowym tekście w konkretnym kodowaniu, w jakim języku i kodowaniu jest dana strona. Ponieważ starsze, 8 bitowe strony kodowe miały zwyczaj umieszczać swoje litery narodowe w różnych przedziałach między 128 a 255 i ponieważ każdy język używany przez ludzi ma inny charakterystyczny histogram użycia liter w tekście, ma to szansę zadziałać. To całkiem dziwne, ale zdaje się, że działa to na tyle często, że naiwni twórcy stron internetowych, którzy nigdy nie wiedzieli, że potrzebują nagłówka Content-Type, patrzą na swoją stronę w przeglądarce, a ona wygląda ok, dopóki pewnego dnia nie napiszą czegoś, co nie do końca współgra z rozkładem prawdopodobieństwa liter w ich rodzimym języku, Internet Explorer zadecyduje, że to koreański i tak to wyświetli, jednocześnie udowadniając, tak myślę, że prawo Postela, aby "być konserwatywnym w tym, co się wypowiada i liberalnym w tym, co się akceptuje" nie jest, szczerze, zbyt dobrą zasadą inżynierską. No a co biedny czytelnik takiej strony, która napisana była po bułgarsku a wygląda na koreańską (i nawet nie jednolicie koreańską), może zrobić? Idzie do menu Widok | Kodowanie i stara się wypróbować różne kodowania (jest przynajmniej tuzin kodowań dla języków wschodniej Europy), dopóki strona nie wygląda bardziej przyjaźnie. Jeśli tylko wie, że może to zrobić, czego nie wie większość ludzi.

Rose

Do ostatniej wersji CityDesk-u, programu zarządzającego stronami internetowymi opublikowanemu przez moją firmę zdecydowaliśmy się, że wewnętrznie będziemy używać Unikodu w UCS-2 (dwa bajty), czego używa Visual Basic, COM i Windows NT/2000/XP jako swój natywny typ łańcuchów znaków. W kodzie C++ po prostu deklarujemy łańcuchy znaków jako wchar_t ("wide char") zamiast char i używamy funkcji wcs zamiast funkcji str (na przykład wcscat i wcslen zamiast strcat i strlen). Aby stworzyć łańcuch znaków w UCS-2 w kodzie C musisz po prostu umieścić literkę "L" przed łańcuchem tak, jak tutaj: L"Hello".

W momencie, kiedy CityDesk publikuje stronę internetową, konwertuje ją do UTF-8, który jest obsługiwany przez przeglądarki od wielu lat. W taki sposób zakodowanych jest wszystkich 29 wersji językowych strony Joel on Software i nie słyszałem nawet jednej osoby, która miałaby kłopot z ich oglądaniem.

Ten artykuł staje się raczej długi, a nie mogę omówić wszystkiego, co jest do poznania w zakresie kodowania znaków i Unikodu, ale mam nadzieję, że skoro przeczytałeś aż dotąd, wiesz wystarczająco dużo, żeby wrócić do programowania (używając antybiotyków zamiast pijawek i czarów), z czym Cię teraz zostawię.

Data publikacji oryginału: 8 października, 2003


15 komentarze:

Anonimowy pisze...

Ciekawy artykuł jednak dla mnie tylko dla odświeżenia pamięci na temat sposoób kodowania :)
Każdy programista powinien wiedzieć to, o czym jest mowa wyżej.

BTW. Literówka "przez przeglądareki od wielu lat" - przedostatni akapit

mXs pisze...

Oczywiście, wiadomości są tutaj bardzo podstawowe. Niemniej jednak warto je odświeżyć... a niektórym przybliżyć ;)

Literówka poprawiona - dzięki za zwrócenie uwagi :)

khalas pisze...

Przyjemne odświeżenie tematu.

Anonimowy pisze...

trochę za dużo lania wody ;>

Anonimowy pisze...

to jeszcze ja pokażę literówkę o tu:
"poziome bloki w małymi dyndałkami"

Anonimowy pisze...

Świetne tłumaczenie, wielkie dzięki. :)

Anonimowy pisze...

Jeśli kieruje się artykuł do programistów, to wstawki dla laików są trochę bez sensu. Nie sądziłem że będę komuś marudził o długość wywodu, ale tutaj jest naprawdę niedużo treści, a dużo "ornamentów". Pozdrawiam i zalecam zwięzłość w sprawach dydaktyki, jeśli jest skierowana do osób z jakimiś kompetencjami. Dla laika artykuł byłby pewnie niezły.

mXs pisze...

@Anonimowy nr3: Literówka poprawiona - dzięki :)
@Anonimowy nr4: Dzięki, proszę :)
@Anonimowy nr5: Prawda, taki jego rozwlekły styl. Za mało być może zdań, jak "jeżeli jesteś jedną z tych niewielu osób (...)".

Anonimowy pisze...

A jeśli uznam, że na swojej stronię będę używał kodowania Windows-1250 lub iso? Mimo wszystko wiele witryn przygotowanych z UTF-8 wyświetla się niepoprawnie, dotyczy to nawet kilku znanych internetowych sklepów.

Anonimowy pisze...

Świetny tekst. Dodałbym jeszcze informacje, że czcionka (UTF-8) czcionce nie równa. Możesz mieć świetnie napisany program, ale niepełne czcionki UTF-8 i nadal się męczyć. Przykładowo generatory PDF'ów (php:Zend, perl:PDF:API2) które to mają wbudowane zestawy czcionek UTF-8, ale oczywiście nie wypełnionych (brak polskich znaków).

Warto mieć w czcionki TTF z własnej stajni.

Anonimowy pisze...

no cóż tyle "zachodu", a można było po prosu wy* polskie znaki

Anonimowy pisze...

Artykuł bardzo fajny. Jestem początkujący w programowaniu i sądzę, że dla takich jak ja nieźle przybliża tematykę kodowania. Ciężko czasem znaleźć proste publikacje dla początkujących na bardziej zawiłe tematy.
Dzięki.

Anonimowy pisze...

UCS-2 nie jest tożsame UTF-16, choć są one podobne. Ten pierwszy koduje zawsze dwoma bajtami czyli ma ograniczenie do 65535 znaków (0 sie nie liczy). Drugi również koduje dwoma bajtami, ale czasem koduje po dwie pary bajtów, tak aby obsłużyć wszystkie znaki (>65536). Takie pary to po ang. tzw. "surrogate pair", w różnych systemach są funkcje API do obsługi takich par, więc myślę, że warto o nich wspomnieć w artykule.

Anonimowy pisze...

hmm, no, ok, fajny tekst... tylko co ma html do programowania?...

SasQ pisze...

Arytykuł bardzo dobrze napisany, tylko pod koniec autor sam wpadł w podobną pułapkę, myląc wchar_t z UCS-2. Standard języka C++ nie definiuje, by wchar_t był jakimkolwiek sposobem zapisu Unicode. Określa jedynie, że ten typ służy do przechowywania znaków z "rozszerzonego zestawu znaków danej maszyny". Jeśli dana maszyna używa do tego celu jakiejś formy Unicode, to rzeczywiście możemy nie zauważyć problemu. Ale tak być nie musi...

Prześlij komentarz

Related Posts with Thumbnails