|
| 1 | +# Unicode, Satr ichki tuzilishi |
| 2 | + |
| 3 | +```warn header="Ilg'or bilim" |
| 4 | +Bu bo'lim satr ichki tuzilishiga chuqurroq kiradi. Bu bilimlar agar siz emoji, noyob matematik yoki ieroglif belgilar yoki boshqa noyob simvollar bilan ishlashni rejalashtirgan bo'lsangiz foydali bo'ladi. |
| 5 | +``` |
| 6 | + |
| 7 | +Biz allaqachon bilamizki, JavaScript satrlari [Unicode](https://en.wikipedia.org/wiki/Unicode) ga asoslangan: har bir belgi 1-4 baytlik bayt ketma-ketligi bilan ifodalanadi. |
| 8 | + |
| 9 | +JavaScript bizga quyidagi uchta yozuv usulidan biri bilan uning o'n oltinchi Unicode kodini belgilash orqali satrga belgi kiritish imkonini beradi: |
| 10 | + |
| 11 | +- `\xXX` |
| 12 | + |
| 13 | + `XX` `00` dan `FF` gacha qiymat bilan ikkita o'n oltinchi raqam bo'lishi kerak, keyin `\xXX` Unicode kodi `XX` bo'lgan belgining o'zi. |
| 14 | + |
| 15 | + `\xXX` yozuvi faqat ikkita o'n oltinchi raqamni qo'llab-quvvatlagani uchun, u faqat birinchi 256 ta Unicode belgilari uchun ishlatilishi mumkin. |
| 16 | + |
| 17 | + Bu birinchi 256 ta belgi lotin alifbosi, asosiy sintaksis belgilarining ko'pchiligi va boshqalarni o'z ichiga oladi. Masalan, `"\x7A"` `"z"` (Unicode `U+007A`) bilan bir xil. |
| 18 | + |
| 19 | + ```js run |
| 20 | + alert( "\x7A" ); // z |
| 21 | + alert( "\xA9" ); // ©, mualliflik huquqi belgisi |
| 22 | + ``` |
| 23 | + |
| 24 | +- `\uXXXX` |
| 25 | + `XXXX` aniq 4 ta hex raqam bo'lishi kerak, qiymati `0000` dan `FFFF` gacha, keyin `\uXXXX` Unicode kodi `XXXX` bo'lgan belgi. |
| 26 | +
|
| 27 | + `U+FFFF` dan katta Unicode qiymatlariga ega belgilar ham bu yozuv bilan ifodalanishi mumkin, ammo bu holda biz surrogat juft deb ataladigan narsadan foydalanishimiz kerak (biz surrogat juftlar haqida ushbu bobda keyinroq gaplashamiz). |
| 28 | +
|
| 29 | + ```js run |
| 30 | + alert( "\u00A9" ); // ©, \xA9 bilan bir xil, 4 raqamli hex yozuvdan foydalanib |
| 31 | + alert( "\u044F" ); // я, kirill alifbosi harfi |
| 32 | + alert( "\u2191" ); // ↑, yuqoriga o'q belgisi |
| 33 | + ``` |
| 34 | + |
| 35 | +- `\u{X…XXXXXX}` |
| 36 | +
|
| 37 | + `X…XXXXXX` `0` dan `10FFFF` gacha (Unicode tomonidan belgilangan eng yuqori kod nuqtasi) 1 dan 6 baytgacha o'n oltinchi qiymat bo'lishi kerak. Bu yozuv bizga barcha mavjud Unicode belgilarini osongina ifodalash imkonini beradi. |
| 38 | +
|
| 39 | + ```js run |
| 40 | + alert( "\u{20331}" ); // 佫, noyob xitoy belgisi (uzun Unicode) |
| 41 | + alert( "\u{1F60D}" ); // 😍, tabassumli yuz belgisi (boshqa uzun Unicode) |
| 42 | + ``` |
| 43 | + |
| 44 | +## Surrogat juftlar |
| 45 | + |
| 46 | +Barcha tez-tez ishlatiladigan belgilar 2 baytli kodlarga ega (4 hex raqam). Ko'pgina Yevropa tillaridagi harflar, raqamlar va asosiy birlashtirilgan CJK ideografik to'plamlar (CJK -- Xitoy, Yapon va Koreya yozuv tizimlaridan), 2 baytli tasvirga ega. |
| 47 | + |
| 48 | +Dastlab, JavaScript faqat har bir belgi uchun 2 baytga ruxsat beradigan UTF-16 kodlashtirishga asoslangan edi. Ammo 2 bayt faqat 65536 ta kombinatsiyaga ruxsat beradi va bu Unicode ning har bir mumkin bo'lgan belgisi uchun etarli emas. |
| 49 | +
|
| 50 | +Shuning uchun 2 baytdan ko'proq talab qiladigan noyob belgilar "surrogat juft" deb ataladigan 2 baytli belgilar jufi bilan kodlanadi. |
| 51 | + |
| 52 | +Yon ta'sir sifatida, bunday belgilarning uzunligi `2`: |
| 53 | +
|
| 54 | +```js run |
| 55 | +alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X |
| 56 | +alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY |
| 57 | +alert( '𩷶'.length ); // 2, noyob xitoy belgisi |
| 58 | +``` |
| 59 | +
|
| 60 | +Buning sababi surrogat juftlar JavaScript yaratilgan vaqtda mavjud emas edi va shuning uchun til tomonidan to'g'ri ishlov berilmaydi! |
| 61 | +
|
| 62 | +Yuqoridagi satrlarning har birida biz bitta belgi bor, ammo `length` xususiyati `2` uzunligini ko'rsatadi. |
| 63 | + |
| 64 | +Belgini olish ham qiyin bo'lishi mumkin, chunki ko'pgina til xususiyatlari surrogat juftlarni ikkita belgi sifatida ko'radi. |
| 65 | +
|
| 66 | +Masalan, bu yerda biz chiqishda ikkita g'alati belgini ko'rishimiz mumkin: |
| 67 | +
|
| 68 | +```js run |
| 69 | +alert( '𝒳'[0] ); // g'alati belgilarni ko'rsatadi... |
| 70 | +alert( '𝒳'[1] ); // ...surrogat juftning qismlari |
| 71 | +``` |
| 72 | +
|
| 73 | +Surrogat juft qismlari bir-birisiz ma'noga ega emas. Shuning uchun yuqoridagi misoldagi alertlar aslida axlatni ko'rsatadi. |
| 74 | +
|
| 75 | +Texnik jihatdan, surrogat juftlar ularning kodlari bilan ham aniqlanadi: agar belgi `0xd800..0xdbff` oralig'idagi kodga ega bo'lsa, u surrogat juftning birinchi qismidir. Keyingi belgi (ikkinchi qism) `0xdc00..0xdfff` oralig'idagi kodga ega bo'lishi kerak. Bu oraliqlar standart tomonidan faqat surrogat juftlar uchun ajratilgan. |
| 76 | +
|
| 77 | +Shuning uchun [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) va [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) usullari surrogat juftlar bilan ishlash uchun JavaScript ga qo'shildi. |
| 78 | + |
| 79 | +Ular mohiyatan [String.fromCharCode](mdn:js/String/fromCharCode) va [str.charCodeAt](mdn:js/String/charCodeAt) bilan bir xil, ammo ular surrogat juftlarni to'g'ri ko'radi. |
| 80 | +
|
| 81 | +Bu yerda farqni ko'rish mumkin: |
| 82 | + |
| 83 | +```js run |
| 84 | +// charCodeAt surrogat juftlardan xabardor emas, shuning uchun u 𝒳 ning 1-qismi uchun kodlarni beradi: |
| 85 | +
|
| 86 | +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 |
| 87 | +
|
| 88 | +// codePointAt surrogat juftlardan xabardor |
| 89 | +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, surrogat juftning ikkala qismini o'qiydi |
| 90 | +``` |
| 91 | + |
| 92 | +Aytish kerakki, agar biz 1-pozitsiyadan olsak (va bu yerda ancha noto'g'ri), ikkalasi ham juftning faqat 2-qismini qaytaradi: |
| 93 | + |
| 94 | +```js run |
| 95 | +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 |
| 96 | +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 |
| 97 | +// juftning ma'nosiz 2-yarmi |
| 98 | +``` |
| 99 | + |
| 100 | +<info:iterable> bobida surrogat juftlar bilan ishlashning ko'proq usullarini topasiz. Buning uchun maxsus kutubxonalar ham bor, ammo bu yerda taklif qilish uchun etarlicha mashhur emas. |
| 101 | +
|
| 102 | +````warn header="Xulosa: satrlarni ixtiyoriy nuqtada bo'lish xavfli" |
| 103 | +Biz satrni ixtiyoriy pozitsiyada shunchaki bo'la olmaymiz, masalan `str.slice(0, 4)` ni olib, uni haqiqiy satr deb kutishimiz mumkin, masalan: |
| 104 | +
|
| 105 | +```js run |
| 106 | +alert( 'salom 😂'.slice(0, 4) ); // salom [?] |
| 107 | +``` |
| 108 | +
|
| 109 | +Bu yerda biz chiqishda axlat belgi (tabassum surrogat juftning birinchi yarmi) ni ko'rishimiz mumkin. |
| 110 | +
|
| 111 | +Agar siz surrogat juftlar bilan ishonchli ishlashni niyat qilsangiz, buni yodda tuting. Katta muammo bo'lmasligi mumkin, ammo kamida nima sodir bo'layotganini tushunishingiz kerak. |
| 112 | +```` |
| 113 | +
|
| 114 | +## Diakritik belgilar va normalizatsiya |
| 115 | +
|
| 116 | +Ko'p tillarda uning ustida/ostida belgi bilan asosiy belgidan tashkil topgan belgilar mavjud. |
| 117 | +
|
| 118 | +Masalan, `a` harfi quyidagi belgilar uchun asosiy belgi bo'lishi mumkin: `àáâäãåā`. |
| 119 | +
|
| 120 | +Eng keng tarqalgan "kompozit" belgilar Unicode jadvalida o'zlarining kodiga ega. Ammo ularning hammasi emas, chunki juda ko'p mumkin bo'lgan kombinatsiyalar mavjud. |
| 121 | +
|
| 122 | +Ixtiyoriy kompozitsiyalarni qo'llab-quvvatlash uchun Unicode standarti bizga bir nechta Unicode belgilardan foydalanish imkonini beradi: asosiy belgi va undan keyin uni "bezaydigan" bir yoki ko'p "belgi" belgilari. |
| 123 | +
|
| 124 | +Masalan, agar bizda `S` dan keyin maxsus "ustidagi nuqta" belgisi (kod `\u0307`) bo'lsa, u Ṡ sifatida ko'rsatiladi. |
| 125 | +
|
| 126 | +```js run |
| 127 | +alert( 'S\u0307' ); // Ṡ |
| 128 | +``` |
| 129 | +
|
| 130 | +Agar bizga harf ustida (yoki ostida) qo'shimcha belgi kerak bo'lsa -- muammo yo'q, faqat kerakli belgi belgisini qo'shing. |
| 131 | +
|
| 132 | +Masalan, agar biz "ostidagi nuqta" belgisini (kod `\u0323`) qo'shsak, "ustida va ostida nuqtalar bilan S" ga ega bo'lamiz: `Ṩ`. |
| 133 | +
|
| 134 | +Masalan: |
| 135 | +
|
| 136 | +```js run |
| 137 | +alert( 'S\u0307\u0323' ); // Ṩ |
| 138 | +``` |
| 139 | +
|
| 140 | +Bu katta moslashuvchanlikni ta'minlaydi, ammo qiziqarli muammoni ham: ikkita belgi vizual jihatdan bir xil ko'rinishi mumkin, ammo turli Unicode kompozitsiyalar bilan ifodalanishi mumkin. |
| 141 | +
|
| 142 | +Masalan: |
| 143 | +
|
| 144 | +```js run |
| 145 | +let s1 = 'S\u0307\u0323'; // Ṩ, S + ustidagi nuqta + ostidagi nuqta |
| 146 | +let s2 = 'S\u0323\u0307'; // Ṩ, S + ostidagi nuqta + ustidagi nuqta |
| 147 | +
|
| 148 | +alert( `s1: ${s1}, s2: ${s2}` ); |
| 149 | +
|
| 150 | +alert( s1 == s2 ); // false, garchi belgilar bir xil ko'rinsa ham (?!) |
| 151 | +``` |
| 152 | +
|
| 153 | +Buni hal qilish uchun har bir satrni bitta "normal" shaklga keltiradigan "Unicode normalizatsiya" algoritmi mavjud. |
| 154 | +
|
| 155 | +U [str.normalize()](mdn:js/String/normalize) tomonidan amalga oshiriladi. |
| 156 | +
|
| 157 | +```js run |
| 158 | +alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true |
| 159 | +``` |
| 160 | +
|
| 161 | +Bizning vaziyatimizda `normalize()` aslida 3 ta belgi ketma-ketligini bittaga birlashtirishi qiziq: `\u1e68` (ikkita nuqta bilan S). |
| 162 | +
|
| 163 | +```js run |
| 164 | +alert( "S\u0307\u0323".normalize().length ); // 1 |
| 165 | +
|
| 166 | +alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true |
| 167 | +``` |
| 168 | +
|
| 169 | +Haqiqatda, bu har doim ham shunday emas. Sababi `Ṩ` belgisi "etarlicha keng tarqalgan", shuning uchun Unicode yaratuvchilari uni asosiy jadvalga kiritdilar va unga kod berdilar. |
| 170 | +
|
| 171 | +Agar siz normalizatsiya qoidalari va variantlari haqida ko'proq bilmoqchi bo'lsangiz -- ular Unicode standartining ilovasida tasvirlangan: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), ammo ko'pgina amaliy maqsadlar uchun ushbu bo'limdagi ma'lumotlar etarli. |
0 commit comments