Mundarija (36)
- Bu darsda
- 1. Nega bu kerak?
- 2. u flagi: Unicode rejimi
- 2.1 Eslatma: kod nuqtasi va kod birligi
- 2.2 u nimani o'zgartiradi
- 2.3 Eng xavfli tuzoq: u siz \p{L}
- 3. Unicode xususiyatlari: \p{...}
- 3.1 \p{L} — istalgan alifbodagi harf
- 3.2 Asosiy kategoriyalar
- 3.3 \p{Script=...} — qaysi yozuv
- 3.4 O'zbek apostrofi: ʻ va '
- 3.5 Birikuvchi belgilar
- 3.6 Har tilga mos so'z chegarasi
- 4. Emoji
- 4.1 \p{Emoji} tuzog'i
- 4.2 Bir nechta kod nuqtasidan yig'ilgan emoji
- 4.3 v flagi va \p{RGI_Emoji}
- 5. v flagi: klasslar ustida amallar
- 5.1 v nima
- 5.2 Ayirish -- va kesishish &&
- 5.3 Qat'iyroq klass sintaksisi
- 5.4 Qayerda ishlaydi
- 6. Ko'p uchraydigan xatolar
- 6.1 \p{...} ni flagsiz yozish
- 6.2 ʻ va ' ni bir xil deb o'ylash
- 6.3 \p{Emoji} bilan emoji qidirish
- 6.4 \d ni \p{N} ga almashtirish
- 6.5 Normalizatsiyasiz \p{L}
- 7. Mashqlar
- 1-mashq (oson): Harflar soni
- 2-mashq (o'rta): Aralash alifboli so'z
- 3-mashq (qiyin): Emoji statistikasi
- 4-mashq: Vazifalar qadami — teglar xatosini tuzatish
- 8. Real ishda
- Xulosa
- Manbalar
Unicode regex: u va v flag, \p{L} bilan har qanday alifbo va emoji
Qisqacha:
uflagi regex'ni Unicode rejimiga o'tkazadi. Unda emoji bitta belgi bo'ladi va\p{...}— Unicode xususiyati — ishlay boshlaydi. Masalan,\p{L}— istalgan alifbodagi harf (lotin, kirill, xitoy),\p{N}— raqam,\p{Script=Cyrillic}— faqat kirill.vflagiuning kengaytmasi: klasslar ustida amallar ([\p{L}--[a-z]]— "lotin kichik harfidan boshqa harf") va bir nechta kod nuqtasidan iborat emoji uchun\p{RGI_Emoji}.
Bu darsda
uflagi nimani o'zgartirishini va usiz\p{L}nega jimgina noto'g'ri ishlashini bilasiz.\p{L},\p{Lu},\p{N},\p{Script=Latin}bilan har qanday tildagi harf va raqamni topasiz.- O'zbekcha
oʻdagi belgi va oddiy apostrof regex uchun nega har xil ekanini tushuntirasiz. - Emoji'ni to'g'ri topasiz va
\p{Emoji}ning tuzog'ini bilasiz. vflagi bilan klasslarni ayirasiz va kesishtirasiz.vazifalardagi teglar xatosini Unicode regex bilan tuzatasiz.
Oldin bilishingiz kerak: Unicode va emoji: matn ichki tuzilishi, Belgilar va belgi klasslari, Flaglar va lastIndex tuzog'i, Lookahead va lookbehind.
1. Nega bu kerak?
«Bahor» menyusi ikki tilda: o'zbekcha (lotin) va ruscha. Mehmonlar sharhlarida esa emoji ko'p. Sardorga vazifa: menyudagi taom nomlarini ajratib, alifbo bo'yicha ro'yxat qilish. U bilgan vosita bilan urinib ko'rdi:
const menyu = "Osh — 35000 so'm, Плов, oʻrik sharbati";
console.log(menyu.match(/\w+/g));Konsolda:
[ 'Osh', '35000', 'so', 'm', 'o', 'rik', 'sharbati' ]Uchta muammo birdaniga. so'm ikkiga bo'lindi — bu tanish tuzoq. Ruscha Плов umuman topilmadi. oʻrik ham bo'lindi. Bu yerdagi ʻ belgisiga e'tibor bering — u oddiy apostrof emas, uni birozdan keyin ko'ramiz.
Belgilar va belgi klasslari darsida aytgan edik: \w faqat A–Z, a–z, 0–9 va _. Bu ingliz tili uchun yasalgan klass. Dunyoda esa yuzlab alifbo bor. Ularning hammasini taniydigan vosita — Unicode xususiyatlari. Ular faqat u yoki v flagi bilan ishlaydi.
Shu darsning oxirida vazifalar dagi haqiqiy xatoni ham tuzatamiz: "Non olish #bozor, #uy" matnida teg #bozor, — vergul bilan chiqadi.
2. u flagi: Unicode rejimi
2.1 Eslatma: kod nuqtasi va kod birligi
Unicode va emoji darsidan bilasiz: Unicode har belgiga raqam beradi — kod nuqtasi. JavaScript satri esa ichida 16 bitli kod birliklarini saqlaydi. Ko'p belgiga bitta birlik yetadi. Emoji kabi "katta" belgilar esa ikki birlikdan iborat — surrogat juftlik. Shuning uchun "🍵".length — 2.
Oddiy regex (flagsiz) satrni kod birliklari bo'yicha o'qiydi. U emoji'ni ikki bo'lak deb ko'radi. u flagi bilan esa regex kod nuqtalari bo'yicha o'qiydi: emoji — bitta belgi.
2.2 u nimani o'zgartiradi
Flaglar darsida u ning ikki ta'sirini ko'rgan edik: qat'iy sintaksis va emoji'ni butun olish. To'liq ro'yxat to'rtta:
u siz |
u bilan |
|---|---|
. emoji'ning yarmini oladi |
. butun emoji'ni oladi |
\u{1F375} — ishlamaydi |
\u{1F375} — kod nuqtasi bilan belgi () |
| noto'g'ri yozuv jimgina oddiy matn | noto'g'ri yozuv — SyntaxError |
\p{L} — p{L} matni |
\p{L} — Unicode xususiyati |
Ikkinchi qatorni sinab ko'ramiz. \u{...} — belgini kod nuqtasi bilan yozish, Unicode va emoji darsidagi String.fromCodePoint ning regex'dagi o'xshashi:
console.log(/\u{1F375}/u.test("Choy 🍵")); // true
console.log(/^.$/.test("🍵")); // false
console.log(/^.$/u.test("🍵")); // true^.$ — "matn aynan bitta belgidan iborat". u siz emoji ikki belgi deb hisoblandi va naqsh mos kelmadi.
2.3 Eng xavfli tuzoq: u siz \p{L}
To'rtinchi qator — eng xavflisi. u ni unutsangiz, xato chiqmaydi:
console.log(/\p{L}/.test("Osh")); // false
console.log(/\p{L}/.test("p{L}")); // trueFlagsiz regex'da \p — shunchaki p harfi ("noma'lum escape" — \ tashlab yuboriladi). {L} esa oddiy matn. Natijada naqsh "p{L} degan so'z"ni qidiradi. Kod ishlaydi, lekin mutlaqo boshqa narsa qiladi.
Qoida: \p{...} ko'rgan joyingizda flaglarga qarang — u yoki v bo'lishi shart. Yangi yozilayotgan regex'da u qo'yishni odat qiling: u bunday jim xatolarni SyntaxError ga aylantiradi.
Tekshirib ko'ring:
"🍎🍵".match(/./g).lengthva"🍎🍵".match(/./gu).lengthnima qaytaradi?
Javob
4 va 2. Har emoji — ikki kod birligi. u siz nuqta har birligini alohida belgi deb oldi. u bilan — har emoji bitta kod nuqtasi, demak bitta belgi.
3. Unicode xususiyatlari: \p{...}
3.1 \p{L} — istalgan alifbodagi harf
Unicode har bir belgiga raqamdan tashqari xususiyatlar ham bergan: bu harfmi, raqammi, tinish belgisimi, qaysi yozuvga tegishli. Unicode xususiyati (Unicode property escape) — regex'da shu xususiyat bo'yicha belgi tanlash. Yozilishi: \p{Nomi}.
Kutubxonadagi kitoblarni eslang. Har kitob kartochkasida janri yozilgan: "roman", "she'r", "lug'at". Kutubxonachi "menga hamma romanlarni ber" desa, sarlavhalarni bittalab o'qimaydi — kartochkaga qaraydi. \p{L} ham shunday: "kartochkasida «harf» deb yozilgan hamma belgilar".
L — "Letter" (harf). Maydonda sinang:
Uch narsaga qarang. Birinchidan, ruscha Плов va xitoycha 抓饭 ham "harf". Ikkinchidan, oʻrik butun qoldi — demak ʻ belgisi harf. Uchinchidan, so'm baribir bo'lindi — oddiy apostrof harf emas. Bu farqni alohida bo'limda ko'ramiz.
3.2 Asosiy kategoriyalar
L — umumiy kategoriya (general category). Eng ko'p kerak bo'ladiganlari:
| Yozuv | Ma'nosi | Misol |
|---|---|---|
\p{L} |
harf | a, Ш, 抓 |
\p{Lu} / \p{Ll} |
katta / kichik harf | O, П / o, п |
\p{N} |
raqam (har qanday yozuvda) | 5, ٣, ३ |
\p{P} |
tinish belgisi | ,, !, ' |
Lu — "Letter, uppercase" (katta harf), Ll — "Letter, lowercase" (kichik harf). Xuddi shu tartibda Nd — o'nlik raqam, Lm — "modifikator harf" (birozdan keyin kerak bo'ladi). Uzun nomlar ham ishlaydi: \p{Letter}, \p{Uppercase_Letter}.
Katta P — teskarisi. \P{L} — "harf bo'lmagan har qanday belgi", xuddi \D va \d kabi.
O'zingiz to'ldiring: faqat kichik harflarni topish uchun \p{} yoziladi.
Raqamlar haqida bitta muhim farq:
const matn = "35000 ٣٥ ३५";
console.log(matn.match(/\p{N}+/gu)); // [ '35000', '٣٥', '३५' ]
console.log(matn.match(/\d+/gu)); // [ '35000' ]\p{N} arab va hind raqamlarini ham oldi. \d esa u bilan ham faqat 0–9. Narx yoki telefon maydonida aynan \d kerak: Number("٣٥") — NaN.
Noto'g'ri nom yozsangiz, u rejimi darhol aytadi:
const naqsh = new RegExp("\\p{Harf}", "u");SyntaxError: Invalid regular expression: /\p{Harf}/u: Invalid property nameTarjimasi: "Noto'g'ri xususiyat nomi." Nomlar Unicode standartidan olinadi va inglizcha — o'zingiz o'ylab topa olmaysiz. To'liq ro'yxat MDN'da, "Unicode character class escape" sahifasida.
3.3 \p{Script=...} — qaysi yozuv
Ba'zan "har qanday harf" emas, aniq yozuv kerak: faqat lotin yoki faqat kirill. Buning uchun Script (yozuv) xususiyati bor:
Qisqa shakli — \p{sc=Cyrillic} (sc — "script"). Ko'p ishlatiladigan nomlar: Latin, Cyrillic, Arabic, Han (xitoy ierogliflari), Greek.
Bu qayerda kerak? Masalan, homoglif — ko'rinishi bir xil, lekin har xil alifbodagi harflar. Kirillcha а va lotincha a ko'zga bir xil, kompyuter uchun esa har xil. Firibgarlar shu bilan soxta saytlar nomini yasaydi. Bir so'zda ham lotin, ham kirill bo'lsa — shubhali. Buni 2-mashqda tekshiramiz.
3.4 O'zbek apostrofi: ʻ va '
Endi oʻrik siriga qaytamiz. O'zbek lotin alifbosining rasmiy yozuvida oʻ va gʻ dagi belgi — U+02BB ("modifier letter turned comma"). U oddiy apostrof ' (U+0027) emas. Klaviaturada ko'pincha uning o'rniga ' yoki ’ (U+2019) yoziladi. Ko'zga uchalasi deyarli bir xil — Unicode uchun esa har xil:
console.log(/\p{L}/u.test("ʻ")); // true
console.log(/\p{L}/u.test("'")); // false
console.log(/\p{L}/u.test("\u{2019}")); // false
console.log(/\p{Lm}/u.test("ʻ")); // true| Belgi | Kod | Unicode bo'yicha |
|---|---|---|
ʻ |
U+02BB | harf — Lm (modifikator harf) |
' |
U+0027 | tinish belgisi — P |
’ |
U+2019 | tinish belgisi — P |
Amaliy xulosa: o'zbekcha so'zni to'liq olish uchun [\p{L}'] — "harf yoki oddiy apostrof". ʻ ga alohida qoida kerak emas, u allaqachon \p{L} ichida. ’ ham kerak bo'lsa — klassga qo'shasiz: [\p{L}'’].
Yana bir nozik joy: \p{Script=Latin} ʻ ni olmaydi. U Unicode'da "umumiy" (Common) yozuvga tegishli — bir nechta alifbo ishlatadi. Shuning uchun \p{Script=Latin}+ oʻrik ni o va rik ga bo'ladi. O'zbekcha matn uchun \p{L} ishonchliroq.
3.5 Birikuvchi belgilar
Unicode va emoji darsida normalize() ni ko'rgan edik: Ў harfi bitta kod nuqtasi ham, ikkitasi ham (У + birikuvchi belgi) bo'lishi mumkin. Ikkinchi holatda \p{L} so'zni bo'lib yuboradi — birikuvchi belgi harf emas, u \p{M} ("mark"):
const yoyilgan = "Ўзбек".normalize("NFD");
console.log(yoyilgan.match(/\p{L}+/gu)); // [ 'У', 'збек' ]
const yigilgan = yoyilgan.normalize("NFC");
console.log(yigilgan.match(/\p{L}+/gu)); // [ 'Ўзбек' ]Yechim — regex'dan oldin normalize("NFC"), yoki klassga \p{M} ni qo'shish: [\p{L}\p{M}]+. Foydalanuvchidan kelgan matnda birinchisi odatiy yo'l.
3.6 Har tilga mos so'z chegarasi
Langarlar va so'z chegarasi darsida \b ikki joyda aldagan edi: apostrof yonida va kirill matnda. Lookahead va lookbehind darsida lotin uchun (?<![\w'])...(?![\w']) yasadik va "har tilga moslarini Unicode darsida" degan edik. Endi \w o'rniga [\p{L}\p{N}_']:
Qoida: "so'z belgisi" nima ekanini o'zingiz belgilaysiz — [\p{L}\p{N}_'] — va ikki tomonga inkor lookaround qo'yasiz. \b faqat ASCII \w ni biladi va u bilan ham o'zgarmaydi.
Tekshirib ko'ring:
"Ош osh 抓饭".match(/\p{L}+/gu)va"Ош osh 抓饭".match(/\p{Script=Latin}+/gu)nima qaytaradi?
Javob
Birinchisi — [ 'Ош', 'osh', '抓饭' ]: uch yozuvdagi harflarning hammasi. Ikkinchisi — [ 'osh' ]: faqat lotin yozuvi.
4. Emoji
4.1 \p{Emoji} tuzog'i
Emoji uchun ham xususiyat bor — \p{Emoji}. Lekin uning nomi aldaydi:
const matn = "Choy 🍵, stol #4";
console.log(matn.match(/\p{Emoji}/gu)); // [ '🍵', '#', '4' ]# va 4 ham "emoji"! Sababi: ular emoji ketma-ketligining boshi bo'la oladi (klaviatura tugmasi emoji'si # va raqamdan yig'iladi). Unicode ularni Emoji xususiyati bilan belgilagan. Ekranda rangli rasm sifatida chiqadigan emoji'lar uchun boshqa xususiyat bor — \p{Emoji_Presentation}:
const matn = "Choy 🍵, stol #4";
console.log(matn.match(/\p{Emoji_Presentation}/gu)); // [ '🍵' ]4.2 Bir nechta kod nuqtasidan yig'ilgan emoji
Unicode va emoji darsida ko'rgan edingiz: ba'zi emoji'lar bir nechta kod nuqtasidan yig'iladi. Masalan, bayrog'i — ikkita maxsus harf. — qo'l va teri rangi. Oila emoji'si esa — uchta odam va ular orasidagi "bog'lovchi" belgilar. \p{Emoji_Presentation} bitta kod nuqtasini oladi, shuning uchun bunday emoji bo'laklarga bo'linadi:
const xabar = "Rahmat 👍🏽 🇺🇿";
console.log(xabar.match(/\p{Emoji_Presentation}/gu).length); // 4Ko'zga ikkita emoji, regex uchun — to'rtta bo'lak.
4.3 v flagi va \p{RGI_Emoji}
Bu muammoni v flagi hal qiladi. Unda satr xususiyatlari (properties of strings) bor — bitta belgini emas, butun ketma-ketlikni moslaydigan xususiyatlar. Eng foydalisi — \p{RGI_Emoji}: Unicode tavsiya qilgan (RGI — "Recommended for General Interchange") har qanday to'liq emoji:
Emoji'ni matndan olib tashlash ham shunday:
const sharh = "Choy tayyor 🍵👍🏽 Bahor 🇺🇿!";
const toza = sharh.replace(/\p{RGI_Emoji}/gv, "");
console.log(toza); // Choy tayyor Bahor !Satr xususiyatlari faqat v bilan ishlaydi. u bilan \p{RGI_Emoji} yozsangiz — Invalid property name.
Maslahat: "Ekranda nechta belgi?" degan savolga regex emas,
Intl.Segmenterjavob beradi (Unicode va emoji darsidan).\p{RGI_Emoji}esa emoji'ni topish, sanash yoki olib tashlash uchun.
5. v flagi: klasslar ustida amallar
5.1 v nima
v (unicode sets — "to'plamlar") — u ning 2023-yilda qo'shilgan yangi varianti. U u qila oladigan hamma narsani qiladi va ustiga uchta imkoniyat qo'shadi: satr xususiyatlari (\p{RGI_Emoji}), klasslar ustida amallar va qat'iyroq klass sintaksisi.
u va v ni birga yozib bo'lmaydi — v allaqachon u ni o'z ichiga oladi:
const naqsh = new RegExp("\\p{L}", "uv");SyntaxError: Invalid flags supplied to RegExp constructor 'uv'Tarjimasi: "RegExp konstruktoriga noto'g'ri flaglar berildi." Ikkalasidan bittasini tanlang.
5.2 Ayirish -- va kesishish &&
To'plamlar darsida Set uchun difference va intersection ni ko'rgan edingiz. v flagi xuddi shu amallarni belgi klasslari uchun beradi:
[A--B]— ayirish: A dagi, lekin B da yo'q belgilar;[A&&B]— kesishish: ham A da, ham B da bor belgilar.
const nom = "Plov, Плов, 抓饭";
console.log(nom.match(/[\p{L}--[a-zA-Z]]+/gv)); // [ 'Плов', '抓饭' ][\p{L}--[a-zA-Z]] — "har qanday harf, lekin ASCII lotin harfi emas". Ayirilayotgan qism o'zi ham klass — [a-zA-Z] — shuning uchun qavs ichida qavs. Ichma-ich klass faqat v da mumkin.
Kesishishga misol — "kirill katta harfi":
console.log("Ош Плов osh".match(/[\p{Lu}&&\p{Script=Cyrillic}]/gv));
// [ 'О', 'П' ]Bunday narsalarni u bilan yozish juda qiyin yoki imkonsiz edi.
Maslahat:
vklassiga bir nechta kod nuqtali satrni ham qo'yish mumkin —\q{...}bilan.[\q{🇺🇿|🇰🇿}]— "yoki O'zbekiston bayrog'i, yoki Qozog'iston bayrog'i". Bayroq ikki kod nuqtasi bo'lgani uchun oddiy klassga sig'maydi. Kam kerak bo'ladi — uchratsangiz, taniysiz.
5.3 Qat'iyroq klass sintaksisi
v klass ichida ba'zi belgilarni escape qilishni talab qiladi. Oddiy klassda [(] — "qavs" edi. v da esa:
const naqsh = new RegExp("[(]", "v");SyntaxError: Invalid regular expression: /[(]/v: Invalid character in character classTarjimasi: "Belgi klassida noto'g'ri belgi." v da klass ichidagi (, ), [, ], {, }, /, -, | — escape bilan: [\(]. Ikkilangan tinish belgilari (&&, --, !!) esa amallar uchun band. Sabab — kelajakda yangi sintaksis qo'shilganda eski kod buzilmasligi.
Shuning uchun u dagi regex'ni v ga o'tkazishda klasslarni ko'zdan kechiring: [(-] kabi joylar xato beradi.
5.4 Qayerda ishlaydi
Baseline ma'lumoti bo'yicha:
uflagi va\u{...}— 2016-yildan barcha brauzerlarda;\p{...}xususiyatlari — 2020-yil iyulidan (Chrome 64, Firefox 78, Safari 11.1);vflagi — 2023-yil sentyabridan (Chrome 112, Firefox 116, Safari 17), 2026-yil martidan esa "keng tarqalgan" (Baseline widely available).
Node 24 va Chrome 154 da bu darsdagi hamma misolni sinadik — natijalar bir xil. HTML'ning pattern atributi naqshni v flagi bilan tekshiradi (Mobil klaviatura va kiritish yordamchilari), shuning uchun pattern ichida ham \p{L} yozish mumkin.
Qaysi birini tanlash kerak? Oddiy holatda — u: u ko'proq tanish va ko'p kodda uchraydi. To'plam amallari yoki \p{RGI_Emoji} kerak bo'lsa — v.
Tekshirib ko'ring:
[\p{L}&&\p{Ll}]nivsiz yozish mumkinmi? Uning qisqaroq yozuvi bormi?
Javob
v siz && amal emas — u bilan ham, flagsiz ham boshqacha o'qiladi. Lekin bu misolda amal kerak ham emas: kichik harfning hammasi baribir harf, demak kesishish — shunchaki \p{Ll}. Amallar bir to'plam ikkinchisining qismi bo'lmaganda foydali: [\p{Lu}&&\p{Script=Cyrillic}].
6. Ko'p uchraydigan xatolar
6.1 \p{...} ni flagsiz yozish
/\p{L}+/g xato bermaydi, lekin p{L} matnini qidiradi. Tuzatish: \p bor regex'da har doim u yoki v. ESLint'ning require-unicode-regexp qoidasi (standart to'plamda o'chiq — o'zingiz yoqasiz) har regex'da u yoki v talab qiladi; ko'p jamoalar uni yoqadi (ESLint va Prettier).
6.2 ʻ va ' ni bir xil deb o'ylash
[\p{L}'] oʻrik ni ham, o'rik ni ham oladi, lekin bular har xil satrlar: "oʻrik" === "o'rik" — false. Qidiruv va solishtirishda avval apostroflarni bir xil ko'rinishga keltirish kerak — buni Almashtirish chuqur darsida replace bilan qilamiz.
6.3 \p{Emoji} bilan emoji qidirish
U #, * va raqamlarni ham oladi. Tuzatish: rangli emoji uchun \p{Emoji_Presentation} (u), to'liq emoji uchun \p{RGI_Emoji} (v).
6.4 \d ni \p{N} ga almashtirish
"Unicode yaxshiroq" deb \d o'rniga \p{N} yozsangiz, narx maydoni ٣٥ ni ham qabul qiladi va Number NaN beradi. Tuzatish: son kerak bo'lgan joyda \d.
6.5 Normalizatsiyasiz \p{L}
Boshqa dasturdan nusxalangan matnda Ў ikki kod nuqtasi bo'lishi mumkin. Tuzatish: matn.normalize("NFC") regex'dan oldin.
O'zingiz to'ldiring: kirill harflarini topish uchun \p{Script=} yoziladi.
7. Mashqlar
1-mashq (oson): Harflar soni
harflarSoni(matn) matndagi harflar sonini qaytarsin — har qanday alifbodagi. Raqam, bo'sh joy, tinish belgisi va emoji sanalmasin.
console.log(harflarSoni("Osh — 35000 so'm")); // 6
console.log(harflarSoni("Ош 🍵")); // 2Yechim
function harflarSoni(matn) {
return (matn.match(/\p{L}/gu) ?? []).length;
}
console.log(harflarSoni("Osh — 35000 so'm")); // 6
console.log(harflarSoni("Ош 🍵")); // 2
console.log(harflarSoni("oʻrik")); // 5?? [] — harf bo'lmasa match null qaytaradi. Uchinchi qatorga qarang: oʻrik da 5 ta harf, chunki ʻ ham harf. o'rik da esa 4 ta bo'lardi.
2-mashq (o'rta): Aralash alifboli so'z
aralashmi(soz) — so'zda ham lotin, ham kirill harfi bo'lsa true qaytarsin. Bu homoglif (soxta harf) belgisi. Ishora: ikkita test — \p{Script=Latin} va \p{Script=Cyrillic}.
Sinov uchun so'zlarni kod nuqtalari bilan yasaymiz — \u{...} satrda ham ishlaydi. \u{41C} — kirillcha katta М, ko'zga lotin M dan farqi yo'q.
const sozlar = ["\u{41C}asalan", "Masalan", "Москва", "bozor"];
console.log(sozlar.map(aralashmi)); // [ true, false, false, false ]Yechim
function aralashmi(soz) {
const lotin = /\p{Script=Latin}/u.test(soz);
const kirill = /\p{Script=Cyrillic}/u.test(soz);
return lotin && kirill;
}
const sozlar = ["\u{41C}asalan", "Masalan", "Москва", "bozor"];
console.log(sozlar.map(aralashmi)); // [ true, false, false, false ]Birinchi so'z ko'zga Masalan ga o'xshaydi, lekin boshidagi harf kirillcha. Matndagi homogliflarni topadigan dasturlar va domen nomlaridagi firibgarlikni ushlaydigan tizimlar shu g'oyaga tayanadi.
3-mashq (qiyin): Emoji statistikasi
emojiSoni(matn) matndagi to'liq emoji'lar sonini qaytarsin (bayroq va teri rangli qo'l — bittadan). emojisiz(matn) esa emoji'larni olib tashlab, ortiqcha bo'sh joylarni bittaga keltirsin. Ishora: \p{RGI_Emoji} faqat v flagi bilan; bo'sh joylar — \s+.
const sharh = "Choy tayyor 🍵👍🏽 bilan keldik 🇺🇿";
console.log(emojiSoni(sharh)); // 3
console.log(emojisiz(sharh)); // Choy tayyor bilan keldikYechim
const EMOJI = /\p{RGI_Emoji}/gv;
function emojiSoni(matn) {
return (matn.match(EMOJI) ?? []).length;
}
function emojisiz(matn) {
return matn.replace(EMOJI, "").replace(/\s+/g, " ").trim();
}
const sharh = "Choy tayyor 🍵👍🏽 bilan keldik 🇺🇿";
console.log(emojiSoni(sharh)); // 3
console.log(emojisiz(sharh)); // Choy tayyor bilan keldik
console.log(sharh.length); // 36sharh.length — 36: kod birliklari, ulardan 10 tasi uchta emoji ichida. \p{Emoji_Presentation} bilan sanasangiz, 5 chiqardi — bo'laklar soni. EMOJI regex'i ikki funksiyada ulashilgan: match va replace lastIndex ni o'zi tozalaydi, shuning uchun bu xavfsiz (Flaglar va lastIndex tuzog'i).
4-mashq: Vazifalar qadami — teglar xatosini tuzatish
Bu safar vazifalar ning o'zini tuzatamiz. Branch: fix/teglar-regex.
Xato. royxat.js dagi teglariniOl matnni split(" ") bilan bo'ladi — bo'sh joygacha hammasi teg:
const matn = "Sabzi #bozor, #uy.";
console.log(
matn.split(" ").filter((s) => s.length > 1 && s.startsWith("#")),
);
// [ '#bozor,', '#uy.' ]Brauzerda (v3, haqiqiy chiqish) teglar qatori shunday: Teglar: #bozor — 1, #bozor, — 1, #uy — 1. Bitta teg ikki xil bo'lib qoldi. Xuddi shunday #uy., #bozor🛒, ##, ##bozor ham noto'g'ri teg bo'ladi.
Ko'prik: o'tgan darslardagi naqsh. Lookahead va lookbehind darsidagi mashqda (?<![\w'])#[\w']+ yozgan edik. U vergulni yechadi, lekin vazifalar uchun uchta joyda yetmaydi:
const naqsh = /(?<![\w'])#[\w']+/g;
console.log("Sabzi #bozor, #uy.".match(naqsh)); // [ '#bozor', '#uy' ]
console.log("#ДОМ #қўй".match(naqsh)); // null
console.log("#oʻquv".match(naqsh)); // [ '#o' ]
console.log("'#o'quv' ##bozor".match(naqsh)); // [ '#bozor' ]\wfaqat ASCII — kirill tegi umuman yo'q,#oʻquvesa#oda kesildi (ʻ—\wemas). Yechim —[\p{L}\p{N}_]vauflagi.- Apostrof klass ichida — u istalgan joyda turishi mumkin.
'#o'quv'da teg oldidagi'lookbehind'ni to'xtatdi. Yechim — apostrof faqat ikki harf orasida:(?:['‘’][\p{L}\p{N}_]+)*. ##bozordan#bozorchiqdi — ikkinchi#oldida#turibdi, u esa[\w']emas. Yechim — lookbehind'ga#ni ham qo'shish.
Yechim — u flagli regex. Funksiya nomi, parametri va natijasi (Set, kichik harf) o'zgarmaydi, faqat ichi:
// Oldin (v3, royxat.js)
function teglariniOl(matn) {
return new Set(
matn
.toLowerCase()
.split(" ")
.filter((soz) => soz.length > 1 && soz.startsWith("#")),
);
}// Keyin
// Teg: # dan keyin harf, raqam yoki _ — har qanday alifbo (\p{L}, u
// flagi). Apostrof faqat harflar orasida: #o'quv, #g'isht. ʻ (U+02BB)
// \p{L} ga kiradi; ' ‘ ’ — tinish belgisi, alohida. Oldida harf
// yoki # bo'lsa (Non#uy, ##uy) — teg emas
const TEG =
/(?<![\p{L}\p{N}_#])#[\p{L}\p{N}_]+(?:['‘’][\p{L}\p{N}_]+)*/gu;
function teglariniOl(matn) {
const teglar = matn.match(TEG) ?? [];
return new Set(teglar.map((teg) => teg.toLowerCase()));
}Naqshni bo'laklab o'qiymiz:
| Bo'lak | Ma'nosi | Nega |
|---|---|---|
# |
panjara | — |
[\p{L}\p{N}_]+ |
istalgan alifbodagi harf, raqam, _ |
\w #қўй, #дом ni kesadi; \p{…} faqat u (yoki v) bilan |
(?:['‘’][\p{L}\p{N}_]+)* |
apostrof — faqat ikki harf orasida | #o'quv, #g‘isht, #o’quv butun; '#o'quv' dagi oxirgi ' tegga kirmaydi |
(?<![\p{L}\p{N}_#]) |
oldida harf, raqam yoki # bo'lmasin |
Non#uy, ##bozor — teg emas |
ʻ (U+02BB) va ʼ (U+02BC) klassga yozilmagan: ular Unicode'da harf (Lm), allaqachon \p{L} ichida. Oxirgi g — hammasini topish uchun; moslik yo'q bo'lsa match null qaytaradi, shuning uchun ?? [].
Ikki nozik joy. Birinchisi — toLowerCase() endi moslikdan keyin chaqiriladi. Avval kichik harfga o'tkazilsa, #İstanbul dagi İ ikki kod nuqtasiga (i + birikuvchi belgi) aylanib, regex tegni #i da kesardi. Ikkinchisi — v flagi ham shu naqsh bilan bir xil natija beradi (sinab ko'rildi), lekin to'plam amallari bu yerda kerak emas — shuning uchun u. Emoji (🛒) \p{L} emas, tegga kirmaydi.
Ataylab qilinmagan narsa ham bor: #o'quv va #oʻquv hali ham ikki xil teg. Apostroflarni bir xil ko'rinishga keltirish ilovaning xulqini kengaytiradi, bunday talab esa yo'q.
const TEG = dan keyin qator bo'lingani — ataylab. Kursda keyinroq o'rnatiladigan Prettier (ESLint va Prettier) aynan shunday yozadi.
Tekshiruv. Avtomatik testlar hali yo'q (Birinchi avtomatik test darsida keladi), shuning uchun v3 dagi tekshiruv skriptidan foydalanamiz. tekshiruv/royxat.js oxiriga:
// Teglar (12/#08): bitta vazifadagi teglar, bo'sh joy bilan
const teglar = (matn) => [...VazifalarRoyxati
.dan([{ id: 1, matn, bajarildi: false }])
.tegHisobi().keys()].join(" ");
tekshir("teg: vergul, nuqta", teglar("Sabzi #bozor, #uy."),
"#bozor #uy");
tekshir("teg: o'zbekcha", teglar("#o'quv #g'isht #oʻquv #g’isht"),
"#o'quv #g'isht #oʻquv #g’isht");
tekshir("teg: emoji", teglar("#bozor🛒 #🛒"), "#bozor");
tekshir("teg emas: # ## Non#uy", teglar("# ## Non#uy"), "");
tekshir("teg: katta harf", teglar("#BOZOR #Bozor"), "#bozor");tekshir(nomi, haqiqiy, kutilgan) — skriptdagi yordamchi: teng bo'lsa , aks holda chiqaradi. Haqiqiy chiqish — oldin (v3 kodi bilan, chapda) va keyin (o'ngda):
❌ teg: vergul, nuqta: #bozor, #uy. ✅ teg: vergul, nuqta: #bozor #uy
✅ teg: o'zbekcha: #o'quv #g'isht #oʻquv #g’isht ✅ teg: o'zbekcha: #o'quv #g'isht #oʻquv #g’isht
❌ teg: emoji: #bozor🛒 #🛒 ✅ teg: emoji: #bozor
❌ teg emas: # ## Non#uy: ## ✅ teg emas: # ## Non#uy:
✅ teg: katta harf: #bozor ✅ teg: katta harf: #bozor#o'quv v3 da ham ishlardi — teglar bo'sh joy bilan ajralgani uchun. Bu test yangi regex uni buzmasligini qotirib qo'yadi. Qolgan tekshiruvlar (royxat, paket, saqlash, marshrut skriptlari) v3 bilan bayt-bayt bir xil.
Brauzerda: import'dan keyin "Sabzi #bozor, #uy" vazifasi qo'shiladi va teglar qatori tekshiriladi:
v3: ❌ teglar: vergulsiz: "Teglar: #bozor — 1, #bozor, — 1, #uy — 1" (kutilgan "Teglar: #bozor — 2, #uy — 1")
v3 + #08: ✅ teglar: vergulsiz: "Teglar: #bozor — 2, #uy — 1" → 45/45 "HAMMASI ✅"Qolgan 44 tekshiruv ikkalasida ham bir xil .
Yechim (buyruqlar)
git switch -c fix/teglar-regex
node tekshiruv/royxat.js
git add assets/js/royxat.js tekshiruv/royxat.js
git commit -m "fix: teglar regex bilan ajratiladi — \"#bozor,\" dagi \
vergul tegga yopishmaydi, o'zbekcha apostrof saqlanadi"
git push -u origin fix/teglar-regex
gh pr create --fill
gh pr merge --mergeCommit xabaridagi \ va yangi qator — terminal uchun: qo'shtirnoq ichida ular olib tashlanadi va xabar bitta qator bo'lib qoladi. Bu branch nomi fix/ bilan boshlanadi: bu safar biz xulqni o'zgartirdik — xatoni tuzatdik. Refaktor (xulq o'zgarmaydi) esa refactor/ bilan bo'ladi, buni qismning oxiridagi darslarda ko'rasiz.
8. Real ishda
- Ko'p tilli saytlar. O'zbekistondagi loyihalarda matn lotin, kirill va rus tilida aralash keladi. Qidiruv, teglar, ism tekshiruvi — hammasida
\wemas,\p{L}kerak. - Xavfsizlik. Homoglif hujumlari (
аpple.comdagi kirillchaа) — brauzerlar va pochta xizmatlari aralash yozuvli domenlarni aynanScriptxususiyati bilan aniqlaydi. - Ijtimoiy tarmoq va chatlar. Telegram kabi ilovalarda emoji'ni sanash, xabar uzunligini cheklash, hashtag ajratish —
\p{RGI_Emoji}va\p{L}bilan. - Intervyu. "
uflagi nima qiladi?", "Har qanday tildagi harfni qanday topasiz?", "Nega'😀'.length— 2?" — tez-tez beriladi.
Xulosa
u— Unicode rejimi: emoji bitta belgi,\u{...}, qat'iy sintaksis,\p{...}. Usiz\p{L}jimginap{L}matnini qidiradi.\p{L}— har qanday harf,\p{Lu}/\p{Ll}— katta/kichik,\p{N}— har qanday raqam,\P{...}— teskarisi;\p{Script=Cyrillic}— aniq yozuv.- O'zbekcha
ʻ(U+02BB) — harf,'va’— tinish belgisi; o'zbekcha so'z uchun[\p{L}']. \p{Emoji}raqam va#ni ham oladi; rangli emoji —\p{Emoji_Presentation}, to'liq emoji —\p{RGI_Emoji}(v).v—uning kengaytmasi:--va&&amallari, ichma-ich klass,\q{...}; klass ichida(kabi belgilar escape bilan;uvavbirga emas.- So'z chegarasi har tilda:
(?<![\p{L}\p{N}_'])...(?![\p{L}\p{N}_']).
Keyingi dars: Almashtirish chuqur va xavfsiz dinamik regex — $1, $<nom>, funksiya bilan almashtirish va foydalanuvchi matnidan RegExp.escape bilan xavfsiz regex yasash.
Manbalar
- MDN: "Unicode character class escape: \p{...}, \P{...}", "RegExp.prototype.unicode", "RegExp.prototype.unicodeSets" — developer.mozilla.org
- Unicode Standard Annex #44 (UCD: General_Category, Script), Unicode Technical Standard #51 (Emoji, RGI) — unicode.org
- TC39: "RegExp v flag with set notation and properties of strings" — github.com/tc39/proposal-regexp-v-flag
- web-features 3.40.0:
javascript.builtins.RegExp.unicodeSets— Baseline 2023-09-18, widely 2026-03-18
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!