Tarkibga o'tish

Go’da regular expression bilan ishlash

Regular expression, qisqacha regex, matndagi takrorlanuvchi shaklni ifodalovchi shablondir. U matndan qiymat qidirish, formatni tekshirish, qismlarga ajratish va mos joylarni almashtirishda ishlatiladi.

Masalan, log satrlaridan sana topish, foydalanuvchi nomi formatini tekshirish yoki matndagi ortiqcha bo‘sh joylarni almashtirish mumkin. Regex aniq matnni emas, matnning qanday tuzilishini yozadi.

Regex barcha matn vazifalari uchun kerak emas. Aniq substring uchun strings.Contains(), prefiks uchun strings.HasPrefix(), URL uchun net/url, vaqt uchun time.Parse() ko‘pincha sodda va ishonchliroq.

Birinchi shablon

Quyidagi matndan YYYY-MM-DD ko‘rinishidagi qismni topamiz:

Bugungi sana: 2025-08-31

Shablon:

\d{4}-\d{2}-\d{2}

Bu yerda:

  • \d — ASCII raqam, ya’ni 0dan 9gacha;
  • {4} — oldingi element aynan to‘rt marta;
  • - — oddiy tire belgisi;
  • {2} — oldingi element aynan ikki marta.

Shablon sana ko‘rinishini topadi, lekin qiymat haqiqiy sana ekanini isbotlamaydi. Masalan, 9999-99-99 ham shu regexga mos keladi. Haqiqiy sanani tekshirish uchun topilgan satrni time.Parse("2006-01-02", value) bilan parse qilish kerak.

Asosiy belgilar

Belgi Ma’nosi Misol Mos qiymat
. Yangi qatordan boshqa bitta belgi c.t cat, cut
\d ASCII raqam \d{2} 12
\w ASCII harf, raqam yoki _ \w+ go_123
\s Bo‘sh joy belgisi a\s+b a b, a\tb
+ Bir yoki ko‘p marta a+ a, aaa
* Nol yoki ko‘p marta ba* b, baa
? Nol yoki bir marta colou?r color, colour
{n} Aynan n marta \d{4} 2025
{n,m} ndan mgacha \d{2,4} 12, 2025
^ Matn boshi ^salom boshidagi salom
$ Matn oxiri dunyo$ oxiridagi dunyo
[abc] To‘plamdagi bitta belgi [abc] a, b yoki c
[^0-9] To‘plamga kirmaydigan belgi [^0-9] raqamdan boshqa belgi
a\|b Chap yoki o‘ng variant cat\|dog cat yoki dog
() Guruhlash va natijani tutish (ab)+ ab, abab

Go regexida \d, \w va \b kabi Perl sinflari ASCII qoidalariga asoslanadi. O‘zbek harflari va boshqa Unicode belgilar uchun \p{L} — harf, \p{N} — raqam kabi Unicode sinflaridan foydalaning.

Maxsus belgining o‘zini qidirish uchun uni \ bilan escape qilish kerak. Masalan, . istalgan belgini anglatadi, \. esa oddiy nuqtaga mos keladi.

Go’da regex kompilyatsiya qilish

Go standart kutubxonasidagi regexp paketi regex bilan ishlaydi. Avval matnli pattern *regexp.Regexp obyektiga kompilyatsiya qilinadi.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d{4}-\d{2}-\d{2}`)
    date := re.FindString("Buyurtma sanasi: 2025-08-31")

    fmt.Println(date)
}

Natija:

2025-08-31

Backtick bilan yozilgan raw string ichida \d uchun qo‘shimcha escape kerak emas. Oddiy qo‘shtirnoqli Go satrida ayni pattern "\\d{4}-\\d{2}-\\d{2}" ko‘rinishida yozilardi.

regexp.MustCompile() pattern xato bo‘lsa panic qiladi. Kod ichida oldindan ma’lum, o‘zgarmas pattern uchun bu qulay: xato dastur ishlab chiqilayotgan paytda aniqlanadi.

Qidirish va to‘liq validatsiya farqi

MatchString() satrning istalgan qismi mos kelsa true qaytaradi. Telefon raqami butun satrni egallashi kerak bo‘lsa, ^ va $ chegaralari yoziladi:

package main

import (
    "fmt"
    "regexp"
)

var phonePattern = regexp.MustCompile(`^\+998[0-9]{9}$`)

func main() {
    fmt.Println(phonePattern.MatchString("+998901234567"))
    fmt.Println(phonePattern.MatchString("Telefon: +998901234567"))
    fmt.Println(phonePattern.MatchString("+99890123456"))
}

Natija:

true
false
false

\+ oddiy + belgisini bildiradi. [0-9]{9} mamlakat kodidan keyin aynan to‘qqiz raqam talab qiladi. Chegaralarsiz pattern ikkinchi matn ichidan ham raqamni topib, true qaytarardi.

Regex faqat formatni tekshiradi. Telefon raqami haqiqatan ajratilganini, faol ekanini yoki operator diapazoniga kirishini alohida biznes qoidalari tekshiradi.

Barcha mosliklarni topish

FindAllString() matndagi barcha mos qismlarni qaytaradi:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`[0-9]+`)
    prices := re.FindAllString("Olma 12000, nok 18000, jami 30000", -1)

    fmt.Println(prices)
}

Natija:

[12000 18000 30000]

Ikkinchi argument maksimal natijalar sonidir. -1 barcha mosliklarni, 2 esa dastlabki ikkitasini qaytaradi. Moslik topilmasa, metod nil slice qaytaradi.

Bu misol sonlarni satr sifatida ajratadi. Ular bilan arifmetik amal bajarish uchun har bir qiymatni strconv.Atoi() orqali intga o‘tkazish va xatoni tekshirish kerak.

Guruhlar orqali qismlarni ajratish

Qavs ichidagi pattern tutuvchi guruh (capturing group) yaratadi. FindStringSubmatch() to‘liq moslik va guruhlarni qaytaradi:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`^([a-z]+)-([0-9]+)$`)
    parts := re.FindStringSubmatch("order-42")
    if parts == nil {
        fmt.Println("Format mos emas")
        return
    }

    fmt.Println("To‘liq:", parts[0])
    fmt.Println("Turi:", parts[1])
    fmt.Println("ID:", parts[2])
}

Natija:

To‘liq: order-42
Turi: order
ID: 42

parts[0] to‘liq moslik, keyingi elementlar qavs ichidagi guruhlardir. parts == nil tekshirilmasa, moslik yo‘q paytda indeksga murojaat panic qiladi.

Faqat guruhlash kerak, ammo natijani tutish kerak bo‘lmasa, (?:...) ishlatiladi. Nomlangan guruhlar (?P<name>...) ko‘rinishida yoziladi va SubexpNames() orqali nomlarini olish mumkin.

Matnni almashtirish

ReplaceAllString() barcha mosliklarni almashtiradi. Masalan, ketma-ket bo‘sh joylarni bitta bo‘sh joyga keltiramiz:

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    re := regexp.MustCompile(`\s+`)
    cleaned := re.ReplaceAllString("  Go\tregex\n bilan   ishlaydi  ", " ")

    fmt.Println(strings.TrimSpace(cleaned))
}

Natija:

Go regex bilan ishlaydi

\s+ bir yoki bir nechta whitespace belgisiga mos keladi. Almashtirishdan keyingi bosh va oxirgi bo‘sh joyni strings.TrimSpace() olib tashlaydi. Faqat bo‘sh joylarni normallashtirish uchun strings.Fields() yanada sodda bo‘lishi mumkin; regex murakkabroq almashtirish qoidalarida foydali.

Almashtirish matnidagi $1 yoki ${name} tutuvchi guruh qiymatini bildiradi. Dollar belgisini oddiy matn sifatida qo‘shish kerak bo‘lsa, ReplaceAllString()ning replacement sintaksisini hisobga oling yoki ReplaceAllStringFunc() ishlating.

Tashqaridan kelgan pattern

Pattern konfiguratsiya yoki foydalanuvchidan kelsa, MustCompile() serverni panic bilan to‘xtatishi mumkin. Bunday holatda regexp.Compile() xatosini boshqaring:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    pattern := `[a-z+`

    re, err := regexp.Compile(pattern)
    if err != nil {
        fmt.Println("Noto‘g‘ri pattern:", err)
        return
    }

    fmt.Println(re.MatchString("go"))
}

Natijadagi xato matni Go versiyasiga qarab biroz farq qilishi mumkin:

Noto‘g‘ri pattern: error parsing regexp: missing closing ]: `[a-z+`

Compile() muvaffaqiyatli bo‘lsa, re ishlatishga tayyor bo‘ladi. Web API’da to‘liq ichki parser xatosini mijozga qaytarish o‘rniga tushunarli validatsiya xabari berish ma’qul.

Email va URL validatsiyasi

Quyidagi soddalashtirilgan pattern odatiy email ko‘rinishini tekshiradi:

(?i)^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$

(?i) katta-kichik harfni farqlamaslikni yoqadi. Bu pattern ko‘plab amaliy manzillarni qabul qiladi, ammo email standartining barcha holatlarini ifodalamaydi va domen mavjudligini tekshirmaydi. Account ro‘yxatdan o‘tkazishda yakuniy tekshiruv — tasdiqlash xatini yuborish.

URL’ni murakkab regex bilan to‘liq validatsiya qilish o‘rniga net/url.ParseRequestURI() yoki vazifaga mos parserdan foydalaning. Parser scheme, host, escaping va query kabi qismlarni tuzilmali ko‘rinishda beradi. Regex faqat loyiha talab qilgan tor formatni tekshirish uchun qo‘shimcha qatlam bo‘lishi mumkin.

Go regex dvigatelining xususiyatlari

Go regexp paketi RE2 sintaksisiga asoslanadi va matching vaqtini kirish hajmiga nisbatan chiziqli saqlashga mo‘ljallangan. Ko‘plab backtracking dvigatellarida uchraydigan catastrophic backtracking xavfi shu dizayn bilan cheklanadi.

Buning evaziga ayrim imkoniyatlar qo‘llanmaydi:

  • backreference: \1, \k<name>;
  • oldinga yoki orqaga qarash (lookahead va lookbehind): (?=...), (?!...), (?<=...);
  • shartli va rekursiv patternlar.

Masalan, takrorlangan aynan bir xil so‘zni backreference bilan qidirib bo‘lmaydi. Kerakli qismlarni guruh bilan ajratib, Go kodida solishtirish kerak.

*regexp.Regexp qiymati kompilyatsiyadan keyin bir nechta goroutine tomonidan xavfsiz ishlatilishi mumkin. Doimiy patternni har request ichida qayta kompilyatsiya qilmang. Uni paket darajasida bir marta tayyorlash CPU va allocation sarfini kamaytiradi.

Unicode va bayt indekslari

Go regex matnni UTF-8 kodlangan Unicode code pointlar sifatida ko‘radi. . odatda bitta rune’ga mos keladi. Ammo indeks qaytaradigan metodlar, masalan FindStringIndex(), natijani rune emas, bayt offsetlari sifatida beradi.

O‘zbek va boshqa Unicode harflarini tekshirish uchun:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`^\p{L}+(?:[’']\p{L}+)*$`)

    fmt.Println(re.MatchString("g‘alaba"))
    fmt.Println(re.MatchString("o'zbek"))
    fmt.Println(re.MatchString("go123"))
}

Natija:

true
true
false

\p{L} istalgan Unicode harfiga mos keladi. [’'] tipografik va oddiy apostrofni qabul qiladi. Raqam guruhga kirmagani uchun go123 mos kelmaydi. Real ism validatsiyasi bundan murakkab: tire, bo‘sh joy va turli yozuv tizimlariga oid biznes qoidalarini alohida belgilang.

Keng tarqalgan xatolar

  • Validatsiya patternida ^ va $ni unutish. Natijada satrning kichik mos qismi butun qiymatni haqiqiy qilib ko‘rsatadi.
  • Raw string va oddiy Go string escapingini aralashtirish. Regexlar uchun backtick ko‘pincha o‘qilishi oson.
  • MustCompile()ni foydalanuvchi patterni bilan chaqirish. Noto‘g‘ri pattern serverni panic bilan to‘xtatadi.
  • Har requestda bir xil regexni qayta kompilyatsiya qilish. Tayyor *regexp.Regexpni qayta ishlating.
  • FindStringSubmatch() natijasini nilga tekshirmasdan indekslash.
  • \w barcha Unicode harflarini qamrab oladi deb o‘ylash. Unicode uchun \p{L} kabi sinflarni ishlating.
  • Regex sintaksis mosligini ma’lumotning haqiqiyligi bilan tenglashtirish. Sana, URL, email va telefon uchun semantik tekshiruv ham kerak.
  • Oddiy vazifani murakkab regex bilan hal qilish. Maxsus parser yoki strings funksiyasi kodni aniqroq qiladi.

Interviewda nimalarga e’tibor beriladi?

  • MatchString() qisman moslikni ham qabul qilishi va validatsiyada chegaralar zarurligi.
  • Compile() va MustCompile()ning farqi.
  • Go regexining RE2 asosida chiziqli vaqt kafolatiga ega bo‘lishi.
  • Backreference va lookaround qo‘llanmasligi.
  • FindString, FindAllString, FindStringSubmatch va ReplaceAllString vazifalari.
  • Unicode sinflari va indekslarning bayt offseti sifatida qaytishi.
  • Tayyor *regexp.Regexpni concurrent va takroran ishlatish mumkinligi.

Xulosa

Regex matndagi shakllarni topish, validatsiya qilish va almashtirish uchun ishlatiladi. Go’ning regexp paketi RE2 sintaksisiga asoslanadi va kirish hajmiga nisbatan chiziqli ishlashga mo‘ljallangan. Doimiy patternni bir marta kompilyatsiya qiling, tashqi pattern xatosini boshqaring va regex formatni tekshirishi bilan ma’lumotning haqiqiyligini isbotlashini aralashtirmang.