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
gbayrog’ini qo’shishimiz mumkin. Ammo keyinstr.match(/\w+/g)chaqiruvi matndagi barcha so’zlarni qidiradi, bizga esa4pozitsiyasidagi 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.
Izohlar
<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…)