6 сентябр 2025

Yopishqoq bayroq "y", pozitsiyada qidirish

y bayrog’i manba satrda berilgan pozitsiyada qidiruvni amalga oshirish imkonini beradi.

y bayrog’ining foydalanish holatini tushunish va regexplarning usullarini yaxshiroq anglash uchun amaliy misolni ko’rib chiqamiz.

Regexplar uchun umumiy vazifalardan biri “leksik tahlil”: bizda matn bor, masalan, dasturlash tilida, va uning strukturaviy elementlarini topishimiz kerak. Masalan, HTML teglar va atributlarga ega, JavaScript kodi funksiyalar, o’zgaruvchilar va hokazolarga ega.

Leksik analizatorlar yozish o’zining vositalari va algoritmlari bilan maxsus sohadir, shuning uchun biz u yerga chuqur kirmaymiz, ammo umumiy vazifa bor: berilgan pozitsiyada biror narsani o’qish.

Masalan, bizda let varName = "value" kod satri bor va undan 4 pozitsiyasida boshlanadigan o’zgaruvchi nomini o’qishimiz kerak.

Biz o’zgaruvchi nomini \w+ regexp yordamida qidiramiz. Aslida, JavaScript o’zgaruvchilar nomlari aniq moslik uchun biroz murakkabroq regexp talab qiladi, ammo bu yerda bu muhim emas.

  • str.match(/\w+/) chaqiruvi faqat satrdagi birinchi so’zni (let) topadi. Bu bizga kerak emas.
  • Biz g bayrog’ini qo’shishimiz mumkin. Ammo keyin str.match(/\w+/g) chaqiruvi matndagi barcha so’zlarni qidiradi, bizga esa 4 pozitsiyasidagi bitta so’z kerak. Yana bizga kerak bo’lgan narsa emas.

Xo’sh, berilgan pozitsiyada aniq regexpni qanday qidirish kerak?

regexp.exec(str) usulidan foydalanishga harakat qilaylik.

g va y bayroqlari bo’lmagan regexp uchun bu usul faqat birinchi moslikni qidiradi, u str.match(regexp) kabi ishlaydi.

…Ammo agar g bayrog’i bo’lsa, u str da qidiruvni regexp.lastIndex xususiyatida saqlangan pozitsiyadan boshlaydi. Va agar moslik topsa, regexp.lastIndex ni moslikdan keyin darhol indeksga o’rnatadi.

Boshqacha qilib aytganda, regexp.lastIndex qidiruv uchun boshlang’ich nuqta bo’lib xizmat qiladi, har bir regexp.exec(str) chaqiruvi uni yangi qiymatga o’rnatadi (“oxirgi moslikdan keyin”). Bu, albatta, faqat g bayrog’i bo’lgan taqdirda.

Shunday qilib, regexp.exec(str) ga ketma-ket chaqiruvlar mosliklarni birin-ketin qaytaradi.

Mana bunday chaqiruvlarning misoli:

let str = 'let varName'; // Keling, bu satrdagi barcha so'zlarni topaylik
let regexp = /\w+/g;

alert(regexp.lastIndex); // 0 (dastlab lastIndex=0)

let word1 = regexp.exec(str);
alert(word1[0]); // let (1-so'z)
alert(regexp.lastIndex); // 3 (moslikdan keyingi pozitsiya)

let word2 = regexp.exec(str);
alert(word2[0]); // varName (2-so'z)
alert(regexp.lastIndex); // 11 (moslikdan keyingi pozitsiya)

let word3 = regexp.exec(str);
alert(word3); // null (boshqa moslik yo'q)
alert(regexp.lastIndex); // 0 (qidiruv oxirida qayta o'rnatiladi)

Barcha mosliklarni tsiklda olishimiz mumkin:

let str = 'let varName';
let regexp = /\w+/g;

let result;

while (result = regexp.exec(str)) {
  alert( `${result[0]} ni ${result.index} pozitsiyasida topdi` );
  // let ni 0 pozitsiyasida topdi, keyin
  // varName ni 4 pozitsiyasida topdi
}

regexp.exec ning bunday foydalanishi jarayonni biroz ko’proq nazorat qilish bilan str.matchAll usuliga muqobildir.

Vazifamizga qaytaylik.

Biz qidiruvni berilgan pozitsiyadan boshlash uchun lastIndex ni qo’lda 4 ga o’rnatishimiz mumkin!

Mana shunday:

let str = 'let varName = "value"';

let regexp = /\w+/g; // "g" bayrog'isiz lastIndex xususiyati e'tiborga olinmaydi

regexp.lastIndex = 4;

let word = regexp.exec(str);
alert(word); // varName

Voy! Muammo hal qilindi!

Biz regexp.lastIndex = 4 pozitsiyasidan boshlab \w+ qidiruvini amalga oshirdik.

Natija to’g’ri.

…Ammo kuting, unchalik tez emas.

E’tibor bering: regexp.exec chaqiruvi lastIndex pozitsiyasidan qidirishni boshlaydi va keyin davom etadi. Agar lastIndex pozitsiyasida so’z bo’lmasa, lekin u undan keyin biror joyda bo’lsa, u topiladi:

let str = 'let varName = "value"';

let regexp = /\w+/g;

// 3 pozitsiyasidan qidiruvni boshlash
regexp.lastIndex = 3;

let word = regexp.exec(str);
// 4 pozitsiyasida moslik topdi
alert(word[0]); // varName
alert(word.index); // 4

Leksik tahlil kabi ba’zi vazifalar uchun bu shunchaki noto’g’ri. Bizga matnda berilgan pozitsiyada aniq moslik kerak, undan keyin biror joyda emas. Va y bayrog’i aynan shu uchun.

y bayrog’i regexp.exec ni aniq lastIndex pozitsiyasida qidirish uchun majbur qiladi, undan “boshlash” emas.

Mana y bayrog’i bilan bir xil qidiruv:

let str = 'let varName = "value"';

let regexp = /\w+/y;

regexp.lastIndex = 3;
alert( regexp.exec(str) ); // null (3 pozitsiyasida bo'sh joy bor, so'z emas)

regexp.lastIndex = 4;
alert( regexp.exec(str) ); // varName (4 pozitsiyasida so'z)

Ko’rib turganimizdek, /\w+/y regexp 3 pozitsiyasida mos kelmaydi (g bayrog’idan farqli o’laroq), ammo 4 pozitsiyasida mos keladi.

Bu nafaqat bizga kerak bo’lgan narsa, y bayrog’idan foydalanganda muhim ishlash yutug’i bor.

Tasavvur qiling, bizda uzun matn bor va unda umuman mosliklar yo’q. Keyin g bayrog’i bilan qidiruv matn oxirigacha boradi va hech narsa topmaydi, va bu faqat aniq pozitsiyani tekshiradigan y bayrog’i bilan qidiruvdan sezilarli darajada ko’proq vaqt oladi.

Leksik tahlil kabi vazifalarda odatda u yerda nimamiz borligini tekshirish uchun aniq pozitsiyada ko’plab qidiruvlar bo’ladi. y bayrog’idan foydalanish to’g’ri amalga oshirish va yaxshi ishlash uchun kalitdir.

O'quv qo'llanma xaritasi

Izohlar

izoh berishdan oldin buni o'qing…
  • Agar sizda nimani yaxshilash kerakligi haqida takliflaringiz bo'lsa - iltimos, GitHub muammosini yuboring yoki izoh berish o'rniga so'rov yuboring.
  • Agar siz maqolada biror narsani tushunolmasangiz - iltimos, batafsilroq ma'lumot bering.
  • Bir nechta so'z so'zlarini kiritish uchun <code> yorlig'ini ishlating, bir nechta satrlar uchun - ularni <pre> yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)