re — regular expressions, match, search, findall, sub, groups

~25 daq · Python · Modullar va Standart kutubxona

Muammodan boshlaylik

Vazifalar:

  • Foydalanuvchi kiritgan telefon raqami +998 90 123-45-67 formatidami?
  • Uzun matndan barcha email manzillarni topish
  • "Narx: 120 000 so'm, chegirma 15%" dan sonlarni ajratib olish
  • Loglarda sanani 2026-11-08 dan 08.11.2026 ga almashtirish

String metodlari (find, split, isdigit) bilan bularning har biri — o'nlab qator, va har bir yangi format — yangi kod.

Regular expression (regex) — matnda qolip (pattern) qidirish uchun maxsus til.


Hayotiy o'xshatma

Qidiruv ma'lumotnomasi: "baland bo'yli, ko'zoynakli, qora kurtkali odam". Siz aniq ismni bilmaysiz — lekin belgilar bo'yicha olomon ichidan topasiz. Regex — matn uchun shunday ta'rif: "+998, keyin ikki raqam, keyin yetti raqam".


Birinchi misol

import re

matn = "Bog'lanish: lola@mail.uz yoki aziz@gmail.com"
emaillar = re.findall(r"[\w.]+@[\w.]+\.\w+", matn)
print(emaillar)     # ['lola@mail.uz', 'aziz@gmail.com']

[!INFO] Qoliplarni har doim raw string (r"...") da yozing. Regex da \ ko'p ishlatiladi (\d, \w), oddiy string da esa \ ning o'zi maxsus belgi — r siz "\b" "backspace" belgisiga aylanadi va qolip jim buziladi.


Asosiy belgilar

Belgi sinflari

Qolip Mos keladi
. Istalgan bitta belgi (yangi qatordan tashqari)
\d Raqam 0-9
\w Harf, raqam yoki _
\s Probel, tab, yangi qator
\D, \W, \S Teskarisi: raqam emas, harf emas, probel emas
[abc] a, b yoki c
[a-z], [0-9] Oraliq
[^0-9] Raqamdan boshqa har qanday belgi

Miqdor

Qolip Ma'nosi
* 0 yoki ko'p
+ 1 yoki ko'p
? 0 yoki 1 (ixtiyoriy)
{3} Aynan 3 marta
{2,4} 2 dan 4 gacha

Joylashuv

Qolip Ma'nosi
^ Satr boshi
$ Satr oxiri
\b So'z chegarasi

Maxsus belgilarni ekranlash

., +, *, ?, (, ), [, $, ^ — maxsus. Oddiy belgi sifatida — \ bilan: \., \+, \(.

re.findall(r"\d+", "Narx: 120 000 so'm, chegirma 15%")   # ['120', '000', '15']
re.findall(r"\d+%", "chegirma 15%, keyin 20%")             # ['15%', '20%']

Funksiyalar

Funksiya Nima qiladi Natija
re.match(p, s) Faqat boshidan tekshiradi Match yoki None
re.fullmatch(p, s) Butun satr mosmi Match yoki None
re.search(p, s) Birinchi mosni istalgan joydan Match yoki None
re.findall(p, s) Barcha moslar Ro'yxat
re.finditer(p, s) Barcha moslar — birma-bir Iterator (Match lar)
re.sub(p, yangi, s) Almashtirish Yangi string
re.split(p, s) Qolip bo'yicha bo'lish Ro'yxat

Tekshirish — fullmatch

import re

def telefon_togrimi(t):
    return re.fullmatch(r"\+998\d{9}", t) is not None

print(telefon_togrimi("+998901234567"))    # True
print(telefon_togrimi("+99890123"))        # False
print(telefon_togrimi("+998901234567abc")) # False — fullmatch butun satrni talab qiladi

[!WARNING] Formatni tekshirishda re.match yoki re.search emas, re.fullmatch (yoki ^...$) ishlating. re.match(r"\+998\d{9}", "+998901234567; DROP TABLE") — muvaffaqiyatli, chunki faqat boshini tekshiradi.

Qidirish — search

m = re.search(r"\d{4}-\d{2}-\d{2}", "Buyurtma 2026-11-08 kuni yaratildi")
if m:
    print(m.group())    # 2026-11-08
    print(m.start(), m.end())   # 9 19

Guruhlar — ( )

Qavslar — mos kelgan qismni alohida olish:

m = re.search(r"(\d{4})-(\d{2})-(\d{2})", "Sana: 2026-11-08")
print(m.group(0))   # 2026-11-08 — butun moslik
print(m.group(1))   # 2026
print(m.groups())   # ('2026', '11', '08')

yil, oy, kun = m.groups()

Nomli guruhlar

m = re.search(r"(?P<yil>\d{4})-(?P<oy>\d{2})-(?P<kun>\d{2})", "Sana: 2026-11-08")
print(m["yil"])         # 2026
print(m.groupdict())    # {'yil': '2026', 'oy': '11', 'kun': '08'}

findall va guruhlar

matn = "Lola: +998901112233, Aziz: +998935556677"
print(re.findall(r"(\w+): (\+998\d{9})", matn))
# [('Lola', '+998901112233'), ('Aziz', '+998935556677')]

Guruh bo'lsa — findall butun moslik emas, guruhlarni qaytaradi.


Almashtirish — sub

# sana formatini o'zgartirish — guruhlarga \1, \2 bilan murojaat
print(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3.\2.\1", "2026-11-08 va 2026-12-01"))
# 08.11.2026 va 01.12.2026

# ortiqcha probellar
print(re.sub(r"\s+", " ", "Salom     dunyo   !").strip())   # Salom dunyo !

# telefonni yashirish
print(re.sub(r"(\+998\d{2})\d{5}(\d{2})", r"\1*****\2", "+998901234567"))
# +99890*****67

Funksiya bilan almashtirish

def ikki_barobar(m):
    return str(int(m.group()) * 2)

print(re.sub(r"\d+", ikki_barobar, "3 olma va 5 nok"))   # 6 olma va 10 nok

split

print(re.split(r"[,;\s]+", "olma, nok;uzum  anor"))   # ['olma', 'nok', 'uzum', 'anor']

Bayroqlar va compile

re.findall(r"python", "Python va PYTHON", flags=re.IGNORECASE)   # ['Python', 'PYTHON']
re.findall(r"^\d+", "1-qator\n2-qator", flags=re.MULTILINE)      # ['1', '2']

Ko'p marta ishlatiladigan qolip — oldindan kompilyatsiya:

EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")

for qator in qatorlar:
    if EMAIL.search(qator):
        ...

Ochko'z va ochko'z emas

html = "<b>Salom</b> va <b>Dunyo</b>"
print(re.findall(r"<b>.*</b>", html))    # ['<b>Salom</b> va <b>Dunyo</b>'] — ochko'z
print(re.findall(r"<b>.*?</b>", html))   # ['<b>Salom</b>', '<b>Dunyo</b>'] — ? bilan minimal

Qachon regex ishlatmaslik

# ❌ ortiqcha
re.search(r"salom", matn)
"salom" in matn                    # ✅

re.sub(r",", ";", matn)
matn.replace(",", ";")             # ✅
  • Oddiy qidiruv va almashtirish — string metodlari tezroq va aniqroq
  • HTML/XML tahlili — maxsus kutubxonalar (BeautifulSoup, lxml); regex bilan HTML ni to'g'ri tahlil qilib bo'lmaydi
  • Email ni "mukammal" tekshirish — regex juda murakkab; oddiy tekshiruv + tasdiqlash xati yaxshiroq

[!TIP] Murakkab qoliplarni regex101.com da sinang — har bir qism nimani anglatishini va moslikni vizual ko'rsatadi (Python rejimini tanlang). Va har doim tushunarli izoh qoldiring: bir oydan keyin o'z regex ingizni ham o'qish qiyin bo'ladi.


Tez-tez uchraydigan xatolar

Raw string siz:

re.findall("\bsalom\b", matn)    # ❌ \b — backspace belgisi, hech narsa topilmaydi
re.findall(r"\bsalom\b", matn)   # ✅

Tekshirish uchun match/search — fullmatch kerak.

Nuqtani ekranlamaslik:

re.fullmatch(r"\w+.uz", "mailxuz")    # ❌ True — . istalgan belgi
re.fullmatch(r"\w+\.uz", "mail.uz")   # ✅

None ni tekshirmasdan group():

re.search(r"\d+", "raqam yo'q").group()   # ❌ AttributeError: 'NoneType'

Xulosa

Regex — matnda qolip bo'yicha qidirish, tekshirish va almashtirish tili.

Eslab qoling:

  • Har doim raw string: r"\d+"
  • \d, \w, \s, ., [...]; *, +, ?, {n,m}; ^, $, \b
  • Tekshirish — fullmatch; qidirish — search; hammasi — findall/finditer
  • Guruhlar ( ), nomli (?P<nom>...); sub da \1
  • re.IGNORECASE, re.compile; minimal moslik — .*?
  • Oddiy vazifalar uchun — string metodlari; HTML — maxsus kutubxona

Keyingi bo'lim

45-dars: Generator va yield — lazy evaluation, xotira tejash