Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Tekshiruvning chegaralari
- 2.1 Regex shaklni tekshiradi, haqiqatni emas
- 2.2 Email
- 2.3 Telefon: avval tozala, keyin tekshir
- 2.4 Qoidalar
- 3. Parsing: regex qachon kerak, qachon emas
- 3.1 Regex yaxshi ishlaydigan joy
- 3.2 Regex yomon ishlaydigan joy
- 4. Halokatli backtracking
- 4.1 Bir matnni necha xil bo'lish mumkin
- 4.2 O'lchab ko'ramiz
- 4.3 Sekin, lekin eksponensial emas
- 5. ReDoS
- 5.1 Hujum nima
- 5.2 Haqiqiy hodisalar
- 6. Hujumchi nigohi
- 7. Ko'p uchraydigan xatolar
- 7.1 "Mukammal" email regex'i
- 7.2 Faqat "to'g'ri" matn bilan sinash
- 7.3 Uzunlikni regex'dan keyin tekshirish
- 7.4 Strukturali formatni regex bilan o'qish
- 7.5 Regex sinov maydonida ReDoS'ni sinash
- 8. Mashqlar
- 1-mashq (oson): Ism tekshiruvi — xavfsiz
- 2-mashq (o'rta): Log'dan statistika
- 3-mashq (qiyin): Xavfli naqshni toping
- 4-mashq: Vazifalar qadami — teg regex'ini ReDoS'ga tekshirish
- 9. Real ishda
- Xulosa
- Manbalar
Regex amaliyotda: email va telefon tekshiruvi, parsing va ReDoS xavfi
Qisqacha: Regex matnning shaklini tekshiradi, haqiqatini emas:
ali@exampel.comham "to'g'ri email" bo'lib o'tadi. Tayyor formatlar uchun (JSON, URL, HTML, sana) regex emas, maxsus vosita ishlatiladi. Ichma-ich quantifierli naqsh, masalan^(\w+\s?)+$, deyarli mos keladigan matnda halokatli backtracking qiladi: har qo'shimcha belgi vaqtni ikki baravar oshiradi. Hujumchi buni ataylab qilsa — ReDoS: bitta so'rov serverni soniyalab band qiladi. Himoya — uzunlik chegarasi va bir ma'noli naqsh.
Bu darsda
- Email va telefonni regex bilan qay darajada tekshirish mumkinligini va qayerda to'xtash kerakligini bilasiz.
- Matndan ma'lumot ajratishda (parsing) regex qachon to'g'ri, qachon noto'g'ri vosita ekanini ajrata olasiz.
- Halokatli backtracking nima uchun yuz berishini sanab, Node'da o'lchab ko'rasiz.
- ReDoS hujumini va undan himoyalanish usullarini tushuntira olasiz.
- Xavfli naqshni bir ma'noli, xavfsiz naqshga qayta yozasiz.
Oldin bilishingiz kerak: Quantifierlar: greedy va lazy, Guruhlar, nomlangan guruhlar va alternation, Almashtirish chuqur va xavfsiz dinamik regex, Event loop.
1. Nega bu kerak?
Sardor bron formasidagi "Ism" maydoniga tekshiruv yozdi. Ism — bir yoki bir nechta so'z, so'zlar orasida bo'sh joy. O'zbekcha harflar uchun apostrof ham kerak. U shunday naqsh tuzdi:
const ismNaqshi = /^([\p{L}']+\s?)+$/u;O'qilishi mantiqiy: "harflar, ixtiyoriy bo'sh joy — bir yoki ko'p marta". Dilshod aka, G'ayrat — hammasi o'tdi. Tekshiruv serverga ham qo'yildi.
Bir kuni test qiluvchi maydonga 30 ta a harfi va oxiriga ! yozdi. Forma "qotib qoldi". Server esa 12 soniya boshqa hech kimga javob bermadi — bron ham, menyu ham. Bitta 31 belgili matn butun saytni to'xtatdi.
Bu darsda uchta savolga javob beramiz:
- Regex tekshiruvi aslida nimani kafolatlaydi va nimani yo'q?
- Qachon regex o'rniga boshqa vosita kerak?
- Sardorning naqshi nega "qotdi" va buni qanday oldini olish mumkin?
Bu RegExp mavzusidagi oxirgi dars. Oldingi to'qqizta darsda o'rgangan hamma narsa shu yerda amalda kerak bo'ladi.
2. Tekshiruvning chegaralari
2.1 Regex shaklni tekshiradi, haqiqatni emas
Validatsiya (validation) — kiritilgan qiymat qoidaga mosligini tekshirish. Regex validatsiyaning faqat bitta qismini qiladi: qiymat ko'rinishini. Pochtachi konvertdagi manzil yozuvini tekshira oladi: ko'cha, uy, xonadon bor. Lekin o'sha uyda haqiqatan kim yashashini konvertga qarab bilolmaydi.
Email misolida buni aniq ko'ramiz.
2.2 Email
Email'ning to'liq qoidasi (RFC 5322 — internet standartlari hujjatlaridan biri) shunchalik murakkabki, uni "to'liq" tekshiradigan regex bir necha yuz belgidan iborat. Hatto HTML'ning type="email" maydoni ham standartni ataylab soddalashtirib tekshiradi (Matnli maydonlar darsidan).
Amalda ko'pincha shunday sodda naqsh yetadi: "bo'sh joy va @ siz bo'lak, @, yana shunday bo'lak, nuqta, yana bo'lak":
const emailNaqshi = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailNaqshi.test("ali@example.com")); // true
console.log(emailNaqshi.test("ali+bahor@example.com")); // true
console.log(emailNaqshi.test("ali@example")); // false
console.log(emailNaqshi.test("ali @example.com")); // false
console.log(emailNaqshi.test("ali@exampel.com")); // trueOxirgi qatorga qarang: exampel — imlo xatosi, lekin naqsh uni o'tkazdi. Bunday domen umuman bo'lmasligi ham mumkin. Regex buni bilmaydi va bila olmaydi.
Maydonda bir nechta manzilni birdaniga sinang. Har qator — alohida qiymat, shuning uchun m flagi bor:
Nega "qattiqroq" naqsh yozmaymiz? Chunki qattiq naqsh haqiqiy manzillarni rad eta boshlaydi. ali+bahor@example.com dagi + ham, yangi domen zonalari ham, lotin bo'lmagan harflar ham — hammasi standartga mos. Ularni rad etgan sayt mijozni yo'qotadi.
Email haqiqatan ishlashini bilishning yagona yo'li — unga xat yuborish. Shuning uchun ro'yxatdan o'tishda "pochtangizga kelgan havolani bosing" degan tasdiqlash bor. To'g'ri yo'l:
- Regex bilan sodda shakl tekshiruvi — foydalanuvchi adashib telefon yozmasin.
- Tasdiqlash xati — manzil haqiqatan uniki ekanini isbotlaydi.
2.3 Telefon: avval tozala, keyin tekshir
O'zbek telefon raqami har xil yoziladi: +998 90 000 00 00, (90) 000-00-00, 998900000000. Hammasini bitta naqsh bilan qamrashga urinish — xato yo'l. Naqsh uzun va tushunarsiz bo'ladi, baribir biror yozuv usulini unutasiz.
To'g'ri yo'l — ikki qadam. Avval Belgilar va belgi klasslari darsidagi \D bilan raqamlardan boshqasini olib tashlaymiz. Keyin faqat raqamlar qatorini tekshiramiz:
function telefonmi(kiritilgan) {
const raqamlar = kiritilgan.replace(/\D/g, "");
const toliq = raqamlar.length === 9 ? "998" + raqamlar : raqamlar;
return /^998\d{9}$/.test(toliq);
}
console.log(telefonmi("+998 90 000 00 00")); // true
console.log(telefonmi("(90) 000-00-00")); // true
console.log(telefonmi("90 000 00")); // false
console.log(telefonmi("+7 900 000 00 00")); // falseBu yerda ham regex shaklni tekshirdi: "998 va to'qqiz raqam". Raqam kimga tegishli, u ishlayaptimi — buni faqat SMS kod bilan bilish mumkin.
Yana bir vasvasa — operator kodlarini (90, 91, 93...) naqshga yozib qo'yish. Bu ro'yxat vaqt o'tishi bilan o'zgaradi: yangi kodlar qo'shiladi. Naqshga yozilgan ro'yxat esa eskiradi va yangi raqamli mijozlar ro'yxatdan o'ta olmay qoladi.
2.4 Qoidalar
- Qattiq naqshdan ko'ra sodda naqsh + tasdiqlash (xat, SMS) yaxshi: haqiqiy mijozni rad etish — eng qimmat xato.
- Kiritilgan qiymatni avval tozalang (
trim,\D), keyin tekshiring. - Brauzerdagi tekshiruv — foydalanuvchi uchun qulaylik. Serverda u albatta takrorlanadi (Langarlar va so'z chegarasi darsidagi "Hujumchi nigohi").
Tekshirib ko'ring:
/^[^\s@]+@[^\s@]+\.[^\s@]+$/naqshi"a@b.c"ni qabul qiladimi? Bu manzil haqiqiymi?
Javob
Qabul qiladi: @ dan oldin a, keyin b, nuqta, c — shakl to'g'ri. Haqiqiy ekani esa noma'lum: .c domen zonasi hozir yo'q. Regex shaklni ko'rdi, haqiqatni emas — buni faqat tasdiqlash xati aniqlaydi.
3. Parsing: regex qachon kerak, qachon emas
3.1 Regex yaxshi ishlaydigan joy
Parsing (tahlil) — matndan tuzilgan ma'lumot ajratib olish. Masalan, «Bahor» serveri har bronni log fayliga bitta qator qilib yozadi. Log — dastur ishi haqidagi yozuvlar daftari. Bu qatorlar bir xil shaklda, ya'ni regex uchun qulay:
const log = `19:00 BRON stol=4 kishi=6
19:05 XATO kod=422
19:12 BRON stol=2 kishi=2`;
const naqsh =
/^(?<vaqt>\d\d:\d\d) BRON stol=(?<stol>\d+) kishi=(?<kishi>\d+)$/gm;
const bronlar = [...log.matchAll(naqsh)]
.map((moslik) => ({ ...moslik.groups }));
console.log(bronlar);Konsolda:
[
{ vaqt: '19:00', stol: '4', kishi: '6' },
{ vaqt: '19:12', stol: '2', kishi: '2' }
]Bu yerda o'tgan darslardagi hamma narsa ishladi: nomlangan guruhlar, m flagi bilan har qator alohida, matchAll bilan hamma mosliklar. XATO qatori naqshga mos kelmadi va tushib qoldi. { ...m.groups } — guruhlar obyektidan oddiy obyekt nusxasi.
Regex bunday joyda yaxshi, chunki shart uchta:
- format sizniki yoki qat'iy belgilangan (o'zgarmaydi);
- har yozuv bitta qatorda, ichma-ich tuzilma yo'q;
- naqsh qisqa — bir qarashda o'qiladi.
3.2 Regex yomon ishlaydigan joy
Endi teskari misol. Sardor menyu sahifasidagi HTML'dan narxlarni ajratmoqchi:
const html =
'<p class="narx">35 000</p><p class="narx" id="b">28 000</p>';
console.log(html.match(/<p class="narx">(.*?)<\/p>/g));
// [ '<p class="narx">35 000</p>' ]Ikkinchi narx yo'qoldi — id atributi bor edi va naqsh uni kutmagan. Atributlar tartibi, qo'shtirnoq turi, izohlar, ichma-ich teglar... HTML'ning har bir "erkinligi" naqshni buzadi. HTML uchun DOM bor: querySelectorAll(".narx") (Elementlarni tanlash).
URL bilan ham xuddi shunday:
const manzil = "https://example.com/bron?stol=4&izoh=deraza%20oldi";
console.log(manzil.match(/izoh=([^&]*)/)[1]); // deraza%20oldi
console.log(new URL(manzil).searchParams.get("izoh")); // deraza oldiRegex %20 ni o'zi ochmadi — bu URL'dagi bo'sh joyning kodlangan yozuvi. URL obyekti esa hamma qoidalarni biladi (URL va URLSearchParams).
Qoida: tayyor format uchun tayyor vosita. Uni yozganlar siz hali duch kelmagan holatlarni ham hisobga olgan.
| Ma'lumot | Regex emas, bu |
|---|---|
| JSON | JSON.parse (JSON asoslari) |
| URL va so'rov parametrlari | new URL, URLSearchParams |
| HTML | DOM: querySelector, DOMParser |
| Sana va vaqt | Date, Intl (keyingi darslar) |
| Son | Number, parseFloat |
| Qo'shtirnoqli CSV | CSV kutubxonasi |
Qaror qilishni diagramma ko'rinishida ko'ring. Har savolga "ha" yoki "yo'q" deb javob berib, pastga tushing:
flowchart TD
A["Matndan nimadir kerak"] --> B{"Tayyor format?<br/>JSON, URL, HTML, sana"}
B -- ha --> C["Maxsus vosita:<br/>JSON.parse, new URL,<br/>DOM, Date / Intl"]
B -- yo'q --> D{"Aniq matn<br/>qidirilyaptimi?"}
D -- ha --> E["includes, startsWith,<br/>split, replaceAll"]
D -- yo'q --> F{"Shakl qisqa va<br/>bir qatorlimi?"}
F -- ha --> G["Regex<br/>+ uzunlik chegarasi"]
F -- yo'q --> H["Kichik parser yoki<br/>kutubxona"]Regex — zanjirning oxiridagi vosita. Undan oldin ikki savol bor: "tayyor vosita yo'qmi?" va "oddiy satr metodi yetmaydimi?".
Tekshirib ko'ring: Foydalanuvchi
"35 000 so'm"yozdi, sizga35000soni kerak. Regex kerakmi?
Javob
Kichik regex foydali: Number(matn.replace(/\D/g, "")) — raqam bo'lmagan hamma narsani olib tashlab, songa aylantiradi. Lekin parsingning o'zini Number qiladi, regex faqat tozalaydi. Agar matnda kasr (35 000,50) bo'lishi mumkin bo'lsa, \D vergulni ham o'chirib, xato son beradi — u holda formatni aniq bilish kerak.
4. Halokatli backtracking
4.1 Bir matnni necha xil bo'lish mumkin
Endi Sardorning qotib qolgan formasiga qaytamiz. Naqsh ^([\p{L}']+\s?)+$ edi. Unda quantifier ichida quantifier bor: guruh ichida +, guruhning o'zida ham +. Bunday naqsh ichma-ich quantifier (nested quantifier) deb ataladi.
Quantifierlar darsidan bilasiz: moslik topilmasa, dvigatel orqaga qaytib, boshqa variantni sinaydi. Ichki + va tashqi + birga bitta matnni juda ko'p usulda bo'lishi mumkin. \s? ixtiyoriy — demak bo'sh joy bo'lmasa ham, guruh yangi takrorni boshlay oladi. aaaa matnini guruh takrorlariga qanday bo'lish mumkinligini sanab ko'ramiz:
function bolishlar(matn) {
if (matn.length <= 1) {
return [matn];
}
const natija = [];
for (let i = 1; i < matn.length; i++) {
for (const qolgan of bolishlar(matn.slice(i))) {
natija.push(matn.slice(0, i) + "|" + qolgan);
}
}
natija.push(matn);
return natija;
}
console.log(bolishlar("aaaa"));Konsolda:
[
'a|a|a|a', 'a|a|aa',
'a|aa|a', 'a|aaa',
'aa|a|a', 'aa|aa',
'aaa|a', 'aaaa'
]Sakkizta usul. | — guruhning bir takroridan keyingisiga o'tish joyi. Funksiya rekursiya bilan ishlaydi: birinchi bo'lakni tanlab, qolganini yana bo'ladi.
Har yangi harf usullar sonini ikki baravar oshiradi: harflar orasidagi har joyda "bo'lish yoki bo'lmaslik" tanlovi bor. n ta harf uchun bu 2 ** (n - 1):
for (const n of [4, 10, 20, 30]) {
console.log(n, 2 ** (n - 1));
}Konsolda:
4 8
10 512
20 524288
30 53687091230 ta harf — yarim milliarddan ortiq usul. Matn oxirida ! turibdi va u [\p{L}'] ga ham, $ ga ham mos kelmaydi. Shuning uchun hech bir usul ishlamaydi. Lekin dvigatel buni bilmaydi va har birini sinab chiqadi. Bu halokatli backtracking (catastrophic backtracking) — dvigatel cheksizdek tuyuladigan orqaga qaytishlarga botib qoladi.
O'zingiz to'ldiring: 5 ta harfli aaaaa ni guruh takrorlariga bo'lish usullari soni — 2 ** 4, ya'ni .
Muhim nozik joy: matn mos kelsa (! siz), dvigatel birinchi urinishdayoq muvaffaqiyat topadi va darhol to'xtaydi. Xavf faqat "deyarli mos keladigan" matnda — oxirida bitta noto'g'ri belgi bo'lsa. Oddiy sinovda hamma narsa tez ishlaydi, shuning uchun xato yillab sezilmay yuradi.
4.2 O'lchab ko'ramiz
Sanash — nazariya. Endi haqiqiy vaqtni Node 24 da o'lchaymiz. performance.now() — millisekundlarni kasr bilan beradigan aniq soat:
// O'lchov: Node 24.21.0, natijalar kompyuterga qarab farq qiladi
const yomon = /^([\p{L}']+\s?)+$/u;
for (const n of [20, 22, 24, 26]) {
const matn = "a".repeat(n) + "!";
const boshlandi = performance.now();
yomon.test(matn);
const ms = performance.now() - boshlandi;
console.log(n, Math.round(ms));
}Diqqat: Bu kodni shu sahifadagi regex maydonida yoki brauzer konsolida sinamang. 30 belgida sahifa 10 soniyadan ko'proq qotadi, 35 belgida — daqiqalab. Faqat terminalda,
nodebilan sinang: qotib qolsa, Ctrl+C bilan to'xtatasiz.
Bizning kompyuterda (Intel Core i5-12500H, Windows 11) chiqqan natijalar — grafikda. Har nuqta — uch ishga tushirishning medianasi: uchta natija tartiblanganda o'rtada turgani. Bitta tasodifiy sekin o'lchov natijani buzmasligi uchun shunday olinadi:
- Xavfli: ^([\p{L}']+\s?)+$
- Xavfsiz: ^[\p{L}']+(?: [\p{L}']+)*$
| Harflar soni | Xavfli: ^([\p{L}']+\s?)+$ | Xavfsiz: ^[\p{L}']+(?: [\p{L}']+)*$ |
|---|---|---|
| 20 | 12 | |
| 22 | 47 | |
| 24 | 200 | |
| 26 | 700 | |
| 28 | 2 900 | |
| 30 | 11 900 | |
| 20 | 0 | |
| 22 | 0 | |
| 24 | 0 | |
| 26 | 0 | |
| 28 | 0 | |
| 30 | 0 |
Manba: O'lchov: Node 24.21.0 (V8 13.6), Intel Core i5-12500H, Windows 11, 2026-10-05; har nuqta — 3 ishga tushirishning medianasi; xavfsiz naqsh har nuqtada 0.01 ms dan kam
Raqamlarga qarang: 20 harf — taxminan 12 ms, 22 — 47 ms, 24 — 200 ms. Har ikki harf qo'shilsa, vaqt to'rt baravar oshadi, ya'ni har harf — ikki baravar. 30 harfda — taxminan 12 soniya. Sanash shuni bashorat qilgan edi. Bunday o'sish eksponensial deb ataladi; algoritmlar tezligini o'lchash usulini (Big-O notatsiyasi) keyingi qismlarda to'liq o'rganamiz.
Pastki chiziq — xavfsiz naqsh, uni birozdan keyin yozamiz. U shu matnlarning hammasida 0.01 ms dan tez ishladi. Grafikda u nolga yopishib qolgan.
4.3 Sekin, lekin eksponensial emas
Ikkinchi, yumshoqroq turi ham bor. /\s+$/ — "oxiridagi bo'sh joylar" — ichma-ich quantifiersiz. Lekin uzun bo'sh joylar qatoridan keyin bo'sh joy bo'lmagan belgi kelsa, dvigatel har boshlanish nuqtasidan qaytadan urinadi. Biz o'lchadik: 10 000 bo'sh joy + x — taxminan 50 ms, 20 000 — 210 ms, 40 000 — 850 ms. Matn ikki baravar uzaysa, vaqt to'rt baravar oshadi. Bu eksponensial emas, kvadratik ("kvadrat" — son o'ziga ko'paytirilgani kabi o'sadi), lekin uzun matnda baribir xavfli. Xuddi shu ishni trimEnd() 40 000 belgida 0.01 ms dan tez qildi.
Tekshirib ko'ring: Sardorning naqshi
"Dilshod aka"bilan tez ishlaydi."Dilshod aka!"bilan-chi? Nega farq bor?
Javob
"Dilshod aka!" sekinroq — chunki mos kelmaydi va dvigatel hamma bo'lish usullarini sinaydi. Bu matnda harflar kam, shuning uchun sekinlik sezilmaydi. Lekin har yangi harf ishni ikki baravar oshiradi. "Dilshod aka" esa mos keladi — birinchi urinishda moslik topiladi va qidiruv to'xtaydi.
5. ReDoS
5.1 Hujum nima
DoS (Denial of Service — xizmatdan chiqarish) — saytni ishlamaydigan holatga keltiruvchi hujum. ReDoS (Regular expression Denial of Service) — buni yomon regex orqali qilish. Hujumchi ko'p kuch sarflamaydi: unga minglab so'rov kerak emas. Bitta qisqa, "deyarli mos keladigan" matn yetadi.
Node'da bu ayniqsa xavfli. Event loop darsidan bilasiz: JavaScript bir threadli. Regex ishlayotganda event loop bloklanadi — boshqa so'rovlar navbatda kutadi. Sardorning serveri 12 soniya hech kimga javob bermagani shundan: bitta test() chaqiruvi butun serverni egallab oldi. Hujumchi har 10 soniyada bitta shunday so'rov yuborsa, sayt umuman ishlamaydi.
Brauzerda zarar kamroq — faqat o'sha foydalanuvchining sahifasi qotadi. Lekin brauzerdagi tekshiruv odatda serverda ham takrorlanadi. Demak xavfli naqsh ikkala joyga ham tushadi.
5.2 Haqiqiy hodisalar
Bu nazariy xavf emas. Ikki mashhur hodisa, ikkalasi ham kompaniyalarning rasmiy hisobotlarida yozilgan:
- Stack Overflow, 2016-yil 20-iyul. Sayt taxminan 34 daqiqa ishlamadi. Sabab — matn oxiridagi bo'sh joylarni olib tashlaydigan regex. Bitta postda 20 000 ga yaqin bo'sh joy belgisi bor edi, va regex uni kvadratik vaqtda tekshirdi — yuqoridagi
\s+$holati. - Cloudflare, 2019-yil 2-iyul. Kompaniya o'z himoya tizimiga yangi qoida qo'shdi. Undagi regexda
.*(?:.*=.*)bo'lagi bor edi — ikkita.*bir xil matnni talashadi. Butun dunyo bo'ylab serverlar protsessori 100% band bo'ldi va Cloudflare orqali ishlaydigan saytlar taxminan 27 daqiqa ochilmadi.
Ikkala holatda ham regex'ni tajribali dasturchilar yozgan va u oddiy sinovlardan o'tgan. Xavf faqat noodatiy matn kelganda paydo bo'ldi.
6. Hujumchi nigohi
Hujumchi ReDoS teshigini qanday topadi?
- Ochiq kodni o'qiydi. Ko'p saytlarning brauzer kodi ochiq — DevTools'da regex'lar ko'rinib turadi. Hujumchi
(...+)+kabi ichma-ich quantifierlarni qidiradi. - Kutubxonalardagi ma'lum teshiklardan foydalanadi. Mashhur npm paketlaridagi ReDoS teshiklari ommaviy bazalarda e'lon qilinadi. Eski versiyani ishlatayotgan sayt — tayyor nishon.
- Avtomatik sinaydi. Har maydonga uzun "deyarli to'g'ri" matn va oxirida noto'g'ri belgi yuboradi, javob vaqtini o'lchaydi.
Darsdagi kod bunga qanday qarshi turadi? Uch qatlam bilan.
Birinchi qatlam — uzunlik chegarasi. Ism 50 belgidan uzun bo'lmaydi. Buni regex'dan oldin oddiy length bilan tekshiring. 50 belgida xavfli naqsh ham soatlab ishlashi mumkin, shuning uchun chegara yolg'iz yetmaydi — lekin u ikkinchi qatlamdagi xatoni yumshatadi.
Ikkinchi qatlam — bir ma'noli naqsh. Matnni guruh takrorlariga faqat bitta usulda bo'lish mumkin bo'lsin:
const ismNaqshi = /^[\p{L}']+(?: [\p{L}']+)*$/u;
console.log(ismNaqshi.test("Dilshod aka")); // true
console.log(ismNaqshi.test("G'ayrat")); // true
console.log(ismNaqshi.test("Dilshod aka")); // false
console.log(ismNaqshi.test("a".repeat(30) + "!")); // falseFarqi kichik ko'rinadi, lekin hal qiluvchi. Takrorlanuvchi guruh (?: [\p{L}']+) endi majburiy bo'sh joy bilan boshlanadi. aaaa ni bo'lishning yagona yo'li qoldi: hammasi birinchi [\p{L}']+ ga tushadi. Bo'sh joy bo'lmagan joyda yangi takror boshlanmaydi. Biz o'lchadik: 100 000 harfli matnda ham bu naqsh 1 ms dan kam ishladi.
Xavfsiz naqshni maydonda sinang — u bilan uzun matn ham qo'rqinchli emas:
Xavfli naqshni tanib olish uchun o'zingizga bitta savol bering: "bir xil belgini ikki xil quantifier talashishi mumkinmi?" (a+)+, (\w+\s?)+, (a|a)*, .*.*= — hammasida javob "ha".
Uchinchi qatlam — vositalar.
- ESLint plagini
eslint-plugin-regexp(2026-10 da 3.3.1) — kod yozish paytida xavfli naqshlarni ko'rsatadi. ESLint'ni ESLint va Prettier darsida o'rnatamiz. - Chiziqli dvigatel. Google'ning RE2 dvigateli backtracking qilmaydi va har doim matn uzunligiga proporsional vaqtda ishlaydi. Node uchun
re2paketi bor (2026-10 da 1.27.0). Narxi: u orqaga havolalar (\1) va lookaround'ni qo'llamaydi. Foydalanuvchi o'z naqshini yozadigan "rivojlangan qidiruv" kabi joylarda aynan shunday dvigatel ishlatiladi. - Ishni alohida thread'ga chiqarish. Og'ir tekshiruvni asosiy thread'dan tashqarida, vaqt chegarasi bilan bajarish mumkin. Brauzerda buning uchun Web Workers bor — ularni keyingi qismda o'rganamiz.
7. Ko'p uchraydigan xatolar
7.1 "Mukammal" email regex'i
Internetdan topilgan 200 belgilik email naqshi haqiqiy manzillarni rad etadi, imlo xatolarini esa baribir o'tkazadi. Ba'zilarida ichma-ich quantifier ham bor. Tuzatish: sodda shakl tekshiruvi (^[^\s@]+@[^\s@]+\.[^\s@]+$) + tasdiqlash xati.
7.2 Faqat "to'g'ri" matn bilan sinash
Regex "Dilshod aka" bilan tez ishladi — demak hammasi joyida, deb o'ylash. Xavf mos kelmaydigan uzun matnda. Tuzatish: har tekshiruv regex'ini kamida uch xil matn bilan sinang: to'g'ri, qisqa noto'g'ri, uzun "deyarli to'g'ri" + oxirida begona belgi.
7.3 Uzunlikni regex'dan keyin tekshirish
if (naqsh.test(ism) && ism.length <= 50) — regex baribir butun uzun matnda ishlaydi. Tuzatish: arzon tekshiruv birinchi: ism.length <= 50 && naqsh.test(ism). && birinchi shart false bo'lsa, ikkinchisini umuman bajarmaydi.
7.4 Strukturali formatni regex bilan o'qish
HTML, JSON, URL'ni regex bilan "parsing" qilish birinchi kutilmagan yozuvda buziladi. Tuzatish: DOM, JSON.parse, URL.
7.5 Regex sinov maydonida ReDoS'ni sinash
Xavfli naqshni regex101 yoki shu sahifadagi maydonga 30+ belgili matn bilan qo'ysangiz, brauzer tabi qotadi. Tuzatish: xavfli naqshlarni faqat terminalda node bilan, kichik n dan boshlab sinang.
O'zingiz to'ldiring: bitta yomon regex bilan serverni band qilib qo'yish hujumi qisqacha deb ataladi.
8. Mashqlar
1-mashq (oson): Ism tekshiruvi — xavfsiz
ismTogrimi(ism) funksiyasini yozing. Ism avval trim qilinsin, uzunligi 2 dan 50 gacha bo'lsin va xavfsiz naqshga mos kelsin: so'zlar (harflar va apostrof) bitta bo'sh joy bilan ajralgan.
console.log(ismTogrimi(" Dilshod aka ")); // true
console.log(ismTogrimi("A")); // false
console.log(ismTogrimi("a".repeat(60))); // false
console.log(ismTogrimi("Ali2")); // falseYechim
const ISM_NAQSHI = /^[\p{L}']+(?: [\p{L}']+)*$/u;
function ismTogrimi(ism) {
const toza = ism.trim();
const uzunlikTogri = toza.length >= 2 && toza.length <= 50;
return uzunlikTogri && ISM_NAQSHI.test(toza);
}
console.log(ismTogrimi(" Dilshod aka ")); // true
console.log(ismTogrimi("A")); // false
console.log(ismTogrimi("a".repeat(60))); // false
console.log(ismTogrimi("Ali2")); // falseUzunlik shartlari && zanjirining boshida — uzun matn regex'gacha yetib bormaydi. Naqshda ichma-ich quantifier bor, lekin takrorlanuvchi guruh majburiy bo'sh joy bilan boshlanadi, shuning uchun u bir ma'noli.
2-mashq (o'rta): Log'dan statistika
«Bahor» log'idan bron qatorlarini ajrating va jami mehmonlar sonini hisoblang. Format: 19:00 BRON stol=4 kishi=6; boshqa turdagi qatorlar (XATO, TOLOV) e'tiborga olinmasin. Ishora: nomlangan guruhlar, m va g flaglari, matchAll, reduce.
const log = `19:00 BRON stol=4 kishi=6
19:05 XATO kod=422
19:12 BRON stol=2 kishi=2
19:30 TOLOV summa=140000`;
console.log(mehmonlarSoni(log)); // 8Yechim
const BRON = /^\d\d:\d\d BRON stol=\d+ kishi=(?<kishi>\d+)$/gm;
function mehmonlarSoni(log) {
return [...log.matchAll(BRON)].reduce(
(jami, moslik) => jami + Number(moslik.groups.kishi),
0,
);
}
const log = `19:00 BRON stol=4 kishi=6
19:05 XATO kod=422
19:12 BRON stol=2 kishi=2
19:30 TOLOV summa=140000`;
console.log(mehmonlarSoni(log)); // 8Faqat kerakli guruh nomlandi — kishi. ^ va $ m flagi bilan har qatorning boshi va oxiri, shuning uchun XATO va TOLOV qatorlari tushib qoldi. g flagi matchAll uchun majburiy.
3-mashq (qiyin): Xavfli naqshni toping
Quyidagi uchta naqshdan qaysi biri ReDoS'ga zaif? Avval o'ylab javob bering, keyin terminalda o'lchab tekshiring: har naqshni "1".repeat(n) + "x" matni bilan n = 16, 18, 20, 22 uchun sinang. Zaif naqshni xavfsiz qilib qayta yozing.
const a = /^\d+(?:\.\d+)?$/; // narx: 35000 yoki 35000.50
const b = /^(\d+\.?)+$/; // versiya: 1.2.3
const c = /^[\d ]+$/; // telefon raqamlari va bo'sh joyYechim
Zaif — b. Unda guruh ichida \d+, guruhning o'zida +, nuqta esa ? bilan ixtiyoriy. Demak nuqtasiz 1111 ni guruh takrorlariga 1|111, 11|11... kabi ko'p usulda bo'lish mumkin. a da ixtiyoriy qism faqat bir marta keladi, c da esa bitta klass — bo'lish usuli yagona.
// Natijalar kompyuterga qarab farq qiladi — faqat o'sish muhim
const naqshlar = {
a: /^\d+(?:\.\d+)?$/,
b: /^(\d+\.?)+$/,
c: /^[\d ]+$/,
};
for (const [nom, naqsh] of Object.entries(naqshlar)) {
const vaqtlar = [16, 18, 20, 22].map((n) => {
const boshlandi = performance.now();
naqsh.test("1".repeat(n) + "x");
return Math.round(performance.now() - boshlandi);
});
console.log(nom, vaqtlar.join(" "));
}
const xavfsiz = /^\d+(?:\.\d+)*$/;
console.log(xavfsiz.test("1.2.3"), xavfsiz.test("1..2"));Bizda (Node 24): a va c — hamma n da 0 ms. b — 20 belgida taxminan 10 ms, 22 belgida taxminan 40 ms: har ikki belgida to'rt baravarga yaqin o'sish. Birinchi o'lchov (16) ba'zan kutilganidan katta chiqadi — V8 regex'ni birinchi chaqiruvlarda sekinroq rejimda bajaradi, keyin tezlashtiradi. Xavfsiz variantda takror majburiy nuqta bilan boshlanadi: (?:\.\d+)*. Oxirgi qator true false chiqaradi: 1.2.3 to'g'ri, ikki nuqta ketma-ket — yo'q.
4-mashq: Vazifalar qadami — teg regex'ini ReDoS'ga tekshirish
Unicode regex darsida vazifalar dagi teglariniOl TEG naqshiga o'tkazildi. Unda ham ichma-ich takrorlanish bor: [\p{L}\p{N}_]+(?:['‘’][\p{L}\p{N}_]+)*. Xavflimi? kurs/mashqlar/12/10-redos/teg-olchov.mjs faylida TEG ni royxat.js dan aynan ko'chiring va uni to'rt xil og'ir matnda o'lchang: uzun harflar, ko'p apostrof, ko'p #, ko'p teg. Uzunlik — 10 000, 100 000 va 1 000 000 belgi. vazifalar kodini o'zgartirmang.
Yechim
// Natijalar kompyuterga qarab farq qiladi
const TEG =
/(?<![\p{L}\p{N}_#])#[\p{L}\p{N}_]+(?:['‘’][\p{L}\p{N}_]+)*/gu;
function olchaVaChiqar(nom, matn) {
const boshlandi = performance.now();
const teglar = matn.match(TEG) ?? [];
const ms = performance.now() - boshlandi;
console.log(`${nom}: ${matn.length} belgi, ${teglar.length} teg, ` +
`${ms.toFixed(1)} ms`);
}
for (const n of [10_000, 100_000, 1_000_000]) {
olchaVaChiqar("harflar", "#" + "a".repeat(n) + "!");
olchaVaChiqar("apostroflar", "#" + "a'".repeat(n / 2) + "'!");
olchaVaChiqar("panjaralar", "#".repeat(n));
olchaVaChiqar("teglar", "#a ".repeat(n / 3));
}Bizda (Node 24, i5-12500H) eng og'ir holat — 1 000 000 belgida 333 333 ta teg: taxminan 25 ms. Ko'p apostrofli bitta uzun teg — taxminan 13 ms. Asosiysi: matn 10 baravar uzaysa, vaqt ham taxminan 10 baravar oshadi — chiziqli o'sish, portlash yo'q. Sabab — darsdagi qoida: takrorlanuvchi guruh (?:['‘’]...) majburiy apostrof bilan boshlanadi. Harflarni ichki + va tashqi * o'rtasida bo'lishning yagona usuli bor. 10_000 dagi pastki chiziq — sonni o'qishga qulay qilish uchun (Son yozish shakllari).
git add 12/10-redos/teg-olchov.mjs
git commit -m "12/10: teg regex'i ReDoS'ga o'lchandi — chiziqli"9. Real ishda
- Forma tekshiruvi. Frontend va backend bitta tekshiruv qoidasini bo'lishadi. Zod kabi sxema kutubxonalari (kursda alohida o'rganamiz) email va URL uchun tayyor, sinalgan tekshiruvlar beradi — o'zingiz yozgan regex'dan ko'ra ishonchliroq.
- Xavfsizlik auditi.
npm auditpaketlardagi ma'lum teshiklarni, jumladan ReDoS'ni ko'rsatadi. Kod review'da ichma-ich quantifierli regex — alohida savol beriladigan joy. - Intervyu. "ReDoS nima?", "Email'ni regex bilan tekshirish yetarlimi?", "Regex bilan HTML'ni parsing qilsa bo'ladimi?" — middle darajadagi intervyularda tez-tez so'raladi.
Xulosa
- Regex shaklni tekshiradi: email va telefon haqiqatini faqat tasdiqlash (xat, SMS) isbotlaydi; sodda naqsh qattiq naqshdan yaxshi.
- Telefon: avval
\Dbilan tozalash, keyin qisqa naqsh; operator kodlarini naqshga yozmang. - Tayyor format uchun tayyor vosita:
JSON.parse,URL, DOM. Regex — bir qatorli, o'zingiz bilgan formatlar uchun. - Ichma-ich quantifier bir matnni ko'p usulda bo'ladi; mos kelmaydigan matnda bu halokatli backtracking — har belgi vaqtni ikki baravar oshiradi.
- ReDoS — shu xatoni ataylab ishlatish; Node'da u butun serverni bloklaydi.
- Himoya: uzunlik chegarasi regex'dan oldin, bir ma'noli naqsh (takror majburiy ajratgich bilan boshlanadi),
eslint-plugin-regexp, kerak bo'lsa RE2.
Keyingi dars: Date asoslari — RegExp'dan keyin sana va vaqt: Date qanday saqlaydi, nega oylar 0 dan boshlanadi va qaysi tuzoqlardan ehtiyot bo'lish kerak.
Manbalar
- MDN: "Regular expressions" (Quantifiers, Backtracking), "Input type=email" — developer.mozilla.org
- OWASP: "Regular expression Denial of Service — ReDoS" — owasp.org
- Stack Exchange: "Outage Postmortem — July 20, 2016" — stackstatus.net
- Cloudflare: "Details of the Cloudflare outage on July 2, 2019" — blog.cloudflare.com
- WHATWG HTML Standard: "Valid e-mail address" — html.spec.whatwg.org
- RE2 — github.com/google/re2;
eslint-plugin-regexp— ota-meshi.github.io/eslint-plugin-regexp
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!