Unicode-ի ստեղծման պատմությունը
Bitstring և binary տվյալների տիպերը հոդվածում տեսանք, որ Elixir-ում string-ը UTF-8-ով կոդավորված binary տիպ է։ Ծանոթացանք նաև բայթերին, code point-երին և byte_size/1 ու String.length/1 ֆունկցիաների տարբերությանը։ Սակայն դեռ չենք պարզել, թե ինչ խնդիր է լուծում Unicode-ը, ինչու ստեղծվեց UTF-8-ը և ինչով են իրարից տարբերվում UTF-8, UTF-16 ու UTF-32 կոդավորումները։
Այս հոդվածում կանդրադառնանք այդ հարցերին։ bitstring-ի և binary-ի կառուցվածքը չենք կրկնի։ Փոխարենը կդիտարկենք տեքստի կոդավորման պատմությունը և Unicode-ի երեք հիմնական կոդավորման ձևերը։
Ինչո՞ւ տեքստը կոդավորման կարիք ունի
Համակարգիչը հիշողության մեջ տառեր կամ պատկերներ չի պահում։ Այն պահում է թվեր, որոնք վերջնականորեն ներկայացվում են բիթերով և բայթերով։ Ուստի տեքստ պահելու համար անհրաժեշտ է համաձայնություն, թե որ թիվը որ նշանն է ներկայացնում։ Այդ համապատասխանությունը սահմանող կանոնների ամբողջությունը կոչվում է նշանների կոդավորում (character encoding)։
Ենթադրենք պայմանավորվել ենք, որ 65 թիվը ներկայացնում է լատինական մեծատառ A-ն։ Այդ դեպքում ծրագիրը 65-ը կարդալիս կարող է էկրանին ցուցադրել A։ Սակայն մեկ այլ ծրագիր պետք է իմանա նույն կանոնը։ Հակառակ դեպքում այն նույն թիվը կարող է բոլորովին այլ նշան համարել։
Խնդիրը հենց թիվը չէ։ Խնդիրն այն է, թե ուղարկողն ու ստացողը արդյո՞ք նույն կոդավորումն են օգտագործում։
ASCII-ն և դրա սահմանափակումները
Համակարգիչների զարգացման սկզբնական շրջանում լայն տարածում ստացավ ASCII կոդավորումը։ Անվանումը կազմվել է American Standard Code for Information Interchange բառերից։ ASCII-ն օգտագործում է 7 բիթ և սահմանում է 128 արժեք՝ 0-ից 127։
Այդ արժեքների մեջ կան՝
- լատինական այբուբենի մեծատառերն ու փոքրատառերը,
- թվանշանները,
- կետադրական մի շարք նշաններ,
- այլ տարածված նշաններ, օրինակ՝ նոր տողը ներկայացնող նշանը
ASCII-ում A-ն ներկայացվում է 65 արժեքով, իսկ a-ն՝ 97 արժեքով։ Այդ համապատասխանությունը պահպանվել է նաև Unicode-ում։
iex> ?A
65
iex> ?a
97
ASCII-ն բավարար էր անգլերեն տեքստերի համար, բայց չէր կարող ներկայացնել հայերեն, հունարեն, արաբերեն, չինարեն և բազմաթիվ այլ գրային համակարգեր։ Նույնիսկ լատինական այբուբենի հիմքով ֆրանսերեն կամ գերմաներեն գրելու համար անհրաժեշտ նշանների մի մասը ASCII-ում բացակայում էր։
Հետագայում տարածվեցին 8-բիթանոց կոդավորումներ։ Մեկ բայթը թույլ էր տալիս օգտագործել 256 արժեք։ Առաջին 128-ը սովորաբար պահպանում էին ASCII-ի նշանակությունները, իսկ մնացած արժեքներին տարբեր համակարգեր տարբեր նշաններ էին վերագրում։ Այդպես առաջացան բազմաթիվ կոդավորումներ, օրինակ՝ ISO-8859 ընտանիքը, Windows code page-երը և KOI8 ընտանիքը։
Այս մոտեցմամբ հնարավոր էր սպասարկել առանձին լեզուներ, բայց ընդհանուր համաձայնություն չկար։ Օրինակ՝ 0xC0 բայթը Windows-1252-ում ներկայացնում է որպես À, իսկ Windows-1251-ում՝ կյուրեղատառ (кириллица) А։ Երբ տեքստը կոդավորված է մի տարբերակով, իսկ ծրագիրը փորձում է այն կարդալ մեկ ուրիշով, էկրանին բնականաբար սխալ նշաններ են հայտնվում։
Բացի դրանից, մեկ փաստաթղթում մի քանի գրային համակարգ համատեղելը դժվար է։ Հայերեն, ճապոներեն և արաբերեն պարունակող տեքստը չէր տեղավորվում որևէ մեկ բայթանոց կոդավորման մեջ։ Անհրաժեշտ էր միասնական համակարգ, որտեղ տարբեր լեզուների նշանները կունենային տարբերվող, ֆիքսված արժեքներ։
Unicode-ի ստեղծումը
Unicode-ի ձևավորմանը նախորդել էին Xerox Character Code Standard-ի (XCCS) շուրջ կատարված աշխատանքը և Apple-ում նշանների համընդհանուր համակարգի վերաբերյալ քննարկումները։ 1987 թվականի վերջին Joe Becker-ը, Lee Collins-ը և Mark Davis-ը սկսեցին ուսումնասիրել միասնական կոդավորման գործնական հնարավորությունը։ Նրանք հիմնվում էին Xerox-ում և Apple-ում բազմալեզու համակարգերի մշակման ընթացքում կուտակված փորձի վրա։ Նախապատրաստական աշխատանքներին մասնակցել են նաև Peter Fenwick-ը, Dave Opstad-ը և այլ մասնագետներ։
1987 թվականի դեկտեմբերին Joe Becker-ն առաջարկեց Unicode անվանումը։ 1988 թվականին նա հրապարակեց Unicode 88 նախագիծը։ Փաստաթղթում անվանումը բացատրվում էր որպես unique, unified, universal encoding՝ եզակի, միավորված և համընդհանուր կոդավորում։ Նախագիծն առաջարկում էր 16-բիթանոց միասնական համակարգ, որը պետք է ներկայացներ աշխարհում գործածվող գրեթե բոլոր գրային համակարգերի նշանները և փոխարիներ միմյանց հետ անհամատեղելի բազմաթիվ կոդավորումներին։
Unicode չափանիշի մշակմամբ և պահպանմամբ այսօր զբաղվում է Unicode Consortium կազմակերպությունը։ Այն ոչ միայն code point է հատկացնում նշաններին, այլև սահմանում է դրանց անունները և բազմաթիվ հատկություններ։ Օրինակ՝ տեղեկություն է պարունակում այն մասին, թե նշանը տա՞ռ է, թվանշա՞ն, կետադրական նշա՞ն, գրության ո՞ր ուղղությունն ունի (օրինակ արաբերեն և եբրայերեն գիրը աջից ձախ է) և այլն։
Unicode-ը սերտորեն կապված է ISO/IEC 10646 միջազգային ստանդարտի հետ։ Երկուսն էլ օգտագործում են նշանների նույն հավաքածուն և նույն code point-երը։ Unicode-ը լրացուցիչ սահմանում է այն հատկությունները, որոնք ծրագրերին անհրաժեշտ են տեքստը ճիշտ մշակելու համար։
Նշանը և դրա պատկերը նույնը չեն
Unicode-ի կառուցվածքը հասկանալու համար պետք է տարբերել նշանը և դրա տեսքը։
Նշանը (character) վերացական տեքստային միավոր է։ Օրինակ՝ հայկական մեծատառ Ա-ն նշան է։
Glyph-ը նշանի տեսքն է որևէ տառատեսակում։ Նույն Ա տառը տարբեր տառատեսակներով կարող է տարբեր տեսք ունենալ, բայց շարունակում է մնալ նույն Unicode նշանը։ Unicode-ը սովորաբար չի սահմանում տառի ճշգրիտ պատկերը։ Այն որոշվում է տառատեսակով և տեքստը ցուցադրող ծրագրով։
Միևնույն glyph-ը միշտ չէ, որ նշանակում է նույն նշանը։ Օրինակ՝ լատինական A-ն և կյուրեղատառ(Кириллица) А-ն շատ նման տեսք ունեն, բայց դրանք տարբեր այբուբենների նշաններ են և ունեն տարբեր code point-եր։
Code point-ը
Unicode-ը յուրաքանչյուր կոդավորված նշանի հատկացնում է թիվ, որը կոչվում է code point։ Այն ընդունված է գրել U+ նախածանցով և տասնվեցական թվով։
| Նշան | Unicode անվանում | Code point |
|---|---|---|
A |
LATIN CAPITAL LETTER A | U+0041 |
Ա |
ARMENIAN CAPITAL LETTER AYB | U+0531 |
€ |
EURO SIGN | U+20AC |
😀 |
GRINNING FACE | U+1F600 |
Elixir-ում ? գրառումը վերադարձնում է նշանի code point-ը՝ որպես ամբողջ թիվ։ iex-ը ամբողջ թվերը ցուցադրում է տասական համակարգով․
iex> ?A
65
iex> ?Ա
1329
iex> ?€
8364
iex> ?😀
128512
Նույն արժեքները տասնվեցական տեսքով ստանալու համար կարելի է կիրառել Integer.to_string/2 ֆունկցիան։
iex> Integer.to_string(?A, 16)
"41"
iex> Integer.to_string(?Ա, 16)
"531"
iex> Integer.to_string(?😀, 16)
"1F600"
Արդյունքի սկզբում զրոների բացակայությունը նշանակություն չունի։ 41-ը և 0041-ը նույն թիվն են։ Unicode-ի գրառման մեջ սովորաբար օգտագործվում է առնվազն չորս թվանշան, ուստի գրում ենք U+0041։
Unicode-ի code point-երի տիրույթը
Unicode-ի code point-երի տիրույթը սկսվում է U+0000-ից և ավարտվում U+10FFFF-ով։ Այն բաժանված է 17 plane-ի։ Յուրաքանչյուր plane պարունակում է 65 536 հնարավոր արժեք։
Առաջին plane-ը կոչվում է Basic Multilingual Plane (BMP)։ Այն ընդգրկում է ամենատարածված ժամանակակից գրային համակարգերի մեծ մասը։ Հայկական տառերը նույնպես BMP-ում են՝ հիմնականում U+0530–U+058F հատվածում։
Մնացած 16 plane-երը կոչվում են լրացուցիչ plane-եր։ Դրանցում կան, օրինակ, պատմական գրային համակարգեր, երաժշտական նշաններ և emoji-ների մի մասը։
Տիրույթի ոչ բոլոր արժեքներն են օգտագործվում։ Բացի դրանից, U+D800–U+DFFF միջակայքը վերապահված է UTF-16-ի surrogate code unit-երին։ Այդ արժեքներն ինքնուրույն Unicode նշաններ չեն ներկայացնում։ Code point-ը, որը դուրս է այդ միջակայքից և գտնվում է U+0000–U+10FFFF տիրույթում, կոչվում է Unicode scalar value։
Unicode-ը և UTF-ը տարբեր հասկացություններ են
Unicode-ը պատասխանում է հետևյալ հարցին՝ ո՞ր թիվն է հատկացված տվյալ նշանին։ Օրինակ՝ Ա տառի code point-ը U+0531 է։ Սակայն այդ թիվը դեռ պետք է ներկայացնել համակարգչի հիշողության մեջ կամ փոխանցել ցանցով։
Այստեղ անհրաժեշտ է ևս մեկ կանոն՝ code point-ը code unit-երի հաջորդականության վերածելու եղանակը։ Code unit-ը տվյալ կոդավորման օգտագործած հիմնական թվային միավորն է։ Այն կարող է լինել 8, 16 կամ 32 բիթ։
Unicode-ը սահմանում է երեք հիմնական կոդավորման ձև՝
- UTF-8՝ 8-բիթանոց code unit-երով,
- UTF-16՝ 16-բիթանոց code unit-երով,
- UTF-32՝ 32-բիթանոց code unit-երով։
UTF հապավումը բացվում է որպես Unicode Transformation Format։ Երեք կոդավորման ձևերն էլ կարող են ներկայացնել Unicode-ի բոլոր scalar value-ները։ Նույն տեքստը առանց կորստի հնարավոր է փոխակերպել մեկ UTF ձևից մյուսը։ Տարբերությունը code point-երը պահելու եղանակն է։
UTF-8-ի ստեղծումը
UTF-8-ը ստեղծվեց 1992 թվականի սեպտեմբերին։ Rob Pike-ը ձևակերպեց պահանջները, իսկ Ken Thompson-ը մշակեց կոդավորման կառուցվածքը Plan 9 օպերացիոն համակարգում կիրառելու համար։ Այն սկզբում ունեցել է այլ անվանումներ, այդ թվում՝ FSS-UTF և UTF-2, իսկ հետո ստացել է UTF-8 անվանումը։
UTF-8-ի կարևոր հատկությունն այն է, որ ASCII տեքստը առանց փոփոխության նաև վավեր UTF-8 տեքստ է։ Օրինակ՝ ASCII-ում և UTF-8-ում A-ն ներկայացվում է նույն 0x41 բայթով։ Սա թույլ տվեց նոր կոդավորումը ներդնել առանց ամբողջությամբ վերափոխելու արդեն գոյություն ունեցող բազմաթիվ ֆայլային համակարգեր, ծրագրավորման լեզուների parser-ներ և ցանցային արձանագրություններ։
UTF-8-ի կառուցվածքը
UTF-8-ի code unit-ը մեկ բայթ է։ Code point-ը ներկայացվում է մեկից չորս բայթով։ Անհրաժեշտ բայթերի քանակը կախված է code point-ի արժեքից։
| Code point-երի միջակայք | Բայթերի քանակ | Բիթային կառուցվածք |
|---|---|---|
U+0000–U+007F |
1 | 0xxxxxxx |
U+0080–U+07FF |
2 | 110xxxxx 10xxxxxx |
U+0800–U+FFFF |
3 | 1110xxxx 10xxxxxx 10xxxxxx |
U+10000–U+10FFFF |
4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
U+D800–U+DFFF միջակայքը ներառված չէ վավեր UTF-8 տվյալներում, թեև թվային առումով գտնվում է աղյուսակի երրորդ տողում։ Ինչպես արդեն նշեցինք, այդ արժեքները վերապահված են UTF-16-ի surrogate code unit-երին և Unicode scalar value-ներ չեն։
Աղյուսակի x բիթերի տեղերում գրվում են code point-ի բիթերը։ Առաջին բայթի սկզբի բիթերը ցույց են տալիս ամբողջ հաջորդականության երկարությունը։
0-ով սկսվող բայթը մեկ բայթանոց ASCII նշան է։110-ով սկսվող բայթը երկու բայթանոց հաջորդականության սկիզբն է։1110-ով սկսվող բայթը երեք բայթանոց հաջորդականության սկիզբն է։11110-ով սկսվող բայթը չորս բայթանոց հաջորդականության սկիզբն է։10-ով սկսվող բայթը շարունակության բայթ է և ինքնուրույն code point չի ներկայացնում։
Այս կառուցվածքի շնորհիվ բայթերի հոսքի մեջ կարելի է տարբերել code point-ի առաջին և հաջորդ բայթերը։ Բացի դրանից, յուրաքանչյուր code point ունի միայն մեկ վավեր UTF-8 ներկայացում։
Մեկ բայթանոց UTF-8 ներկայացումը
A տառի code point-ը U+0041 է։ Դրա արժեքը տասնվեցական 41 է, իսկ երկուական տեսքը՝ 1000001։ Քանի որ այն տեղավորվում է 7 բիթում, UTF-8-ը սկզբում ավելացնում է 0։
Code point: U+0041
Կաղապար: 0xxxxxxx
Արդյունք: 01000001
Բայթ: 0x41
Elixir-ում կարող ենք ստուգել այդ բայթը։
iex> inspect("A", binaries: :as_binaries)
"<<65>>"
65-ը տասնվեցական 0x41 արժեքի տասական տեսքն է։
Երկու բայթանոց UTF-8 ներկայացումը
Հայկական Ա տառի code point-ը U+0531 է։ Այն գտնվում է U+0080–U+07FF միջակայքում, ուստի ներկայացվում է երկու բայթով։
Տառի արժեքի բիթերը տեղադրվում են 110xxxxx 10xxxxxx կաղապարի x դիրքերում։
Code point: U+0531
Code point-ի բիթերը: 10100 110001
Կաղապար: 110xxxxx 10xxxxxx
Արդյունք: 11010100 10110001
Տասնվեցական: D4 B1
Տասական տեսքով D4 B1 բայթերը 212 և 177 են։
iex> inspect("Ա", binaries: :as_binaries)
"<<212, 177>>"
iex> <<?Ա::utf8>>
"Ա"
::utf8 գրառումը Elixir-ին հայտնում է, որ code point-ի արժեքը պետք է binary-ում գրել UTF-8 ձևով։
Երեք և չորս բայթանոց ներկայացումները
Եվրոյի նշանի code point-ը U+20AC է։ Այն ներկայացվում է երեք բայթով՝ E2 82 AC։
iex> inspect("€", binaries: :as_binaries)
"<<226, 130, 172>>"
iex> <<?€::utf8>>
"€"
😀 emoji-ի code point-ը U+1F600 է։ Քանի որ այն մեծ է U+FFFF-ից, UTF-8-ում օգտագործվում է չորս բայթ՝ F0 9F 98 80։
iex> inspect("😀", binaries: :as_binaries)
"<<240, 159, 152, 128>>"
iex> <<?😀::utf8>>
"😀"
Այս օրինակները կարելի է ամփոփել հետևյալ կերպ։
| Նշան | Code point | UTF-8 բայթեր | Չափը |
|---|---|---|---|
A |
U+0041 |
41 |
1 բայթ |
Ա |
U+0531 |
D4 B1 |
2 բայթ |
€ |
U+20AC |
E2 82 AC |
3 բայթ |
😀 |
U+1F600 |
F0 9F 98 80 |
4 բայթ |
UTF-16-ը
UTF-16-ն օգտագործում է 16-բիթանոց code unit-եր։ Մեկ code unit-ը երկու բայթ է։ Սակայն սա չի նշանակում, որ յուրաքանչյուր code point միշտ երկու բայթ է զբաղեցնում։
U+0000–U+D7FFևU+E000–U+FFFFտիրույթների code point-երը ներկայացվում են մեկ 16-բիթանոց code unit-ով։U+10000–U+10FFFFտիրույթի code point-երը ներկայացվում են երկու 16-բիթանոց code unit-ով, այսինքն՝ չորս բայթով։
Երկու code unit-ից կազմված ներկայացումը կոչվում է surrogate pair։ Դրա առաջին code unit-ի արժեքը գտնվում է D800–DBFF, իսկ երկրորդինը՝ DC00–DFFF միջակայքում։ Դրանք առանձին վերցրած նշաններ չեն ներկայացնում։ Միայն միասին են ներկայացնում մեկ code point։
Հայերեն Ա տառի code point-ը U+0531 է։ Այն գտնվում է առաջին տիրույթում, ուստի UTF-16-ում ներկայացվում է մեկ 16-բիթանոց code unit-ով՝ զբաղեցնելով երկու բայթ։
😀 նշանի code point-ը U+1F600 է։ Այն գտնվում է երկրորդ տիրույթում, ուստի ներկայացվում է երկու code unit-ով՝ զբաղեցնելով չորս բայթ։
iex> byte_size(<<?Ա::utf16>>)
2
iex> byte_size(<<?😀::utf16>>)
4
UTF-16BE և UTF-16LE
UTF-16-ի յուրաքանչյուր code unit բաղկացած է երկու բայթից։ Օրինակ՝ Ա տառի code point-ը U+0531 է։ Դրա 0531 արժեքը կարելի է բաժանել երկու բայթի՝ 05 և 31։
0531 → 05 31
Ֆայլում պահելու կամ ցանցով փոխանցելու ժամանակ պետք է որոշել, թե այս երկու բայթերից որն է գրվելու առաջինը։
- UTF-16BE տարբերակում սկզբում գրվում է
05, ապա՝31։ - UTF-16LE տարբերակում սկզբում գրվում է
31, ապա՝05։
UTF-16BE: 05 31
UTF-16LE: 31 05
Երկու տարբերակներն էլ ներկայացնում են նույն Ա տառը։ Տարբեր է միայն բայթերի հերթականությունը։
Elixir-ում հերթականությունը կարելի է բացահայտ նշել big կամ little տարբերակիչներով։ Base.encode16/1 ֆունկցիան ստացված բայթերը ցույց է տալիս տասնվեցական համակարգով։
iex> Base.encode16(<<?Ա::utf16-big>>)
"0531"
iex> Base.encode16(<<?Ա::utf16-little>>)
"3105"
Տեքստը կարդացող ծրագիրը պետք է իմանա, թե որ հերթականությունն է օգտագործվել։ Հակառակ դեպքում այն չի կարող ճիշտ մեկնաբանել բայթերը։
Եթե ֆայլի կոդավորումը նշված է պարզապես որպես UTF-16, ֆայլի սկզբում կարող է ավելացվել BOM հատուկ արժեքը։ Այն ծրագրին հայտնում է՝ բայթերը գրված են UTF-16BE, թե UTF-16LE հերթականությամբ։
Եթե հերթականությունն արդեն հստակ նշված է, օրինակ՝ տվյալների ձևաչափը պահանջում է UTF-16LE, BOM-ը սովորաբար անհրաժեշտ չէ։
UTF-32-ը
UTF-32-ում յուրաքանչյուր code point միշտ զբաղեցնում է չորս բայթ։ Կարևոր չէ՝ այն անգլերեն տառ է, հայերեն տառ, թե էմոջի։
Code point-ի արժեքը գրվում է չորս բայթի մեջ։ Եթե այն ամբողջ տարածքը չի զբաղեցնում, սկզբում ավելացվում են զրոներ։
A → U+0041 → 00 00 00 41
Ա → U+0531 → 00 00 05 31
😀 → U+1F600 → 00 01 F6 00
Այսպիսով, UTF-32-ում բոլոր երեք օրինակներն էլ զբաղեցնում են չորս բայթ։
Elixir-ում դա կարելի է ստուգել byte_size/1 ֆունկցիայով։
iex> byte_size(<<?A::utf32>>)
4
iex> byte_size(<<?Ա::utf32>>)
4
iex> byte_size(<<?😀::utf32>>)
4
Elixir-ում utf32 տարբերակն առանց լրացուցիչ նշման օգտագործում է big-endian հերթականությունը։ Base.encode16/1 ֆունկցիայի միջոցով կարող ենք տեսնել ստացված բայթերը տասնվեցական համակարգով։
iex> Base.encode16(<<?Ա::utf32>>)
"00000531"
iex> Base.encode16(<<?😀::utf32>>)
"0001F600"
Ինչպես UTF-16-ը, UTF-32-ը նույնպես ունի բայթերի երկու հնարավոր հերթականություն՝ UTF-32BE և UTF-32LE։
iex> Base.encode16(<<?Ա::utf32-big>>)
"00000531"
iex> Base.encode16(<<?Ա::utf32-little>>)
"31050000"
Երկու արդյունքներն էլ ներկայացնում են նույն Ա տառը։ Տարբեր է միայն չորս բայթերի հերթականությունը։
UTF-32-ի առավելությունն իր պարզ կառուցվածքն է․ յուրաքանչյուր code point միշտ զբաղեցնում է չորս բայթ։ Սակայն դա նաև մեծացնում է տվյալների ծավալը։ Օրինակ՝ UTF-8-ում A տառը զբաղեցնում է մեկ բայթ, իսկ UTF-32-ում՝ չորս։
Այդ պատճառով UTF-32-ը սովորաբար չի օգտագործվում տեքստային ֆայլերում կամ վեբ էջերում։ Այն հիմնականում կարող է օգտագործվել ծրագրերի ներքին աշխատանքում, երբ յուրաքանչյուր code point-ի համար հաստատուն՝ չորս բայթ չափ ունենալը կարևոր է։
UTF-8, UTF-16 և UTF-32 տարբերությունները
Երեք կոդավորման ձևերն էլ ներկայացնում են Unicode-ի նույն նշանները։ Հնարավոր չէ կոդավորման մի ձևով ներկայացնել այնպիսի Unicode նշան, որը մյուսները չեն կարող ներկայացնել։ Տարբերությունը զուտ ներկայացման ձևն ու հատկացվող տարածքն է։
UTF-8-ը փոփոխական երկարությամբ կոդավորում է։ UTF-16-ը նույնպես փոփոխական երկարություն ունի, եթե հաշվում ենք մեկ code point-ի համար անհրաժեշտ code unit-երի քանակը։ Միայն UTF-32-ն է յուրաքանչյուր Unicode scalar value ներկայացնում մեկ code unit-ով։
Սակայն UTF-32-ի մեկ code unit-ը նույնպես պարտադիր չէ, որ համընկնի այն բանի հետ, ինչը մենք մեկ տեսանելի նշան ենք համարում։ Օրինակ՝ որոշ տեսանելի նշաններ կազմված են մի քանի code point-ից։ Այդ տարբերությունը կդիտարկենք հետագայում։
Կա՞ն այլ UTF կոդավորումներ
Unicode-ի ներկայիս չափանիշը սահմանում է երեք կոդավորման ձև՝ UTF-8, UTF-16 և UTF-32։
Գոյություն ունեն նաև UTF անունը պարունակող այլ ձևաչափեր։ Օրինակ՝ UTF-7-ը ստեղծվել էր 7-բիթանոց հաղորդակցման հին համակարգերի համար։ CESU-8-ը և Modified UTF-8-ը կիրառվել են որոշ համակարգերի հետ համատեղելիության նպատակով։ WTF-8-ը հանդիպում է որոշ ծրագրերի ներքին իրականացման մեջ։ Դրանք Unicode-ի երեք հիմնական encoding form-երը չեն և չպետք է ներկայացվեն որպես սովորական UTF-8։ Մասնավորապես, CESU-8 կամ Modified UTF-8 տվյալները կարող են պարունակել բայթերի հաջորդականություններ, որոնք վավեր UTF-8 չեն։
Նոր համակարգ նախագծելիս տեքստի պահպանման և փոխանակման համար սովորաբար ընտրվում է UTF-8, եթե որևէ արտաքին արձանագրություն կամ API այլ կոդավորում չի պահանջում։ Elixir-ի string-երը նույնպես UTF-8-ով են կոդավորվում։
Փորձեք ինքներդ
Բացեք IEx-ը և կատարեք հետևյալ քայլերը։
?A,?Ա,?€և?😀գրառումներով ստացեք չորս նշանների code point-երը։ ԱյնուհետևInteger.to_string/2ֆունկցիայով ցուցադրեք դրանք տասնվեցական տեսքով։inspect/2ֆունկցիայիbinaries: :as_binariesընտրանքով դիտեք նույն նշանների UTF-8 բայթերը։ Համեմատեք արդյունքները հոդվածի աղյուսակի հետ։byte_size/1ֆունկցիայով համեմատեք"A","Ա","€"և"😀"string-երի չափերը։ Բացատրեք, թե ինչու են արդյունքները տարբեր։- Ստեղծեք նույն նշանները
<<code_point::utf8>>,<<code_point::utf16>>և<<code_point::utf32>>գրելաձևերով։ Յուրաքանչյուր դեպքում հաշվեք binary-ի բայթերի քանակը։ ::utf16-bigու::utf16-littleգրելաձևերով ստացեք նույն code point-ի երկու ներկայացումները և համեմատեք բայթերի հերթականությունը։ Նույնը կրկնեք::utf32-bigու::utf32-littleտարբերակներով։
Աղբյուրներ
- The Unicode Standard — Technical Introduction
- Early Years of Unicode
- Chronology of Unicode Version 1.0
- The Unicode Standard, Chapter 2 — General Structure
- The Unicode Standard, Chapter 3 — Conformance
- Unicode FAQ — UTF-8, UTF-16, UTF-32 և BOM
- RFC 3629 — UTF-8, a transformation format of ISO 10646
- Unicode-ի և ISO/IEC 10646-ի կապը
- Elixir
Stringmodule