IlmHamroh
Python kursi/Standart kutubxona1/16-dars24 daqiqa
Mundarija (23)

15.1-dars: Muntazam ifodalar: asoslar

15-QISM — STANDART KUTUBXONA · 1-dars


1. Kirish va motivatsiya

4-qismda satr metodlarini o'rgandik: find, startswith, split, replace. Ular aniq matn bilan ishlaydi. Lekin ko'p vazifada biz aniq matnni emas, shaklni qidiramiz:

  • "matndagi barcha telefon raqamlari" — raqamlar har xil, shakli bir xil,
  • "2026-09-17 ko'rinishidagi sanalar",
  • "ketma-ket kelgan bir nechta bo'shliqni bittaga almashtirish",
  • "foydalanuvchi nomi faqat harf, raqam va _ dan iborat bo'lsinmi?"

Bularni satr metodlari bilan yozish — o'nlab qator for va if. Muntazam ifoda (regular expression, regex) esa shaklni bir qatorda tasvirlaydi:

python
re.findall(r"\+998[0-9]{9}", matn)  # barcha +998XXXXXXXXX raqamlar

Real vaziyat. Ro'yxatdan o'tish formasida ism ^\w+$ bilan tekshirilardi. O'zbek foydalanuvchilar "Oʻgʻiloy" ni oddiy apostrof bilan — O'g'iloy deb yozganda forma "noto'g'ri ism" dedi, chunki ' harf emas. Boshqa tomondan, xuddi shu \d bilan tekshirilgan "yosh" maydoniga kimdir arabcha raqamlar (٢٥) yozdi va ular ham o'tib ketdi. Ikkala xato ham bir sababdan: dasturchi \w va \d aslida nimani bildirishini bilmagan.

Bu darsda muntazam ifodaning tilini o'rganamiz: belgilar, sinflar, miqdorlar, langarlar va bayroqlar — va har birining tuzoqlarini.

Bu darsda:

  • re modulining asosiy funksiyalari: search, match, fullmatch, findall, finditer
  • Nega har doim r"..." — xom satr
  • Maxsus belgilar va ekranlash, re.escape
  • Belgilar sinflari: [...], \d, \w, \s — va Unicode tuzog'i
  • Miqdorlar: *, +, ?, {m,n} — ochko'z va dangasa
  • Langarlar: ^, $, \b, \A, \Z
  • Muqobillar: |
  • Bayroqlar: IGNORECASE, MULTILINE, DOTALL, VERBOSE, ASCII
  • re.compile va Match obyekti

2. Nazariya — chuqur tushuntirish

2.1. Muntazam ifoda nima

Muntazam ifoda — matn shaklini tasvirlovchi kichik til. re moduli bu tildagi naqshni (pattern) holat mashinasiga kompilyatsiya qiladi va matn ustida yurgizadi.

python
import re

m = re.search(r"\d+", "buyurtma 4521 tayyor")
m.group()     # '4521'
m.span()      # (9, 13)
Naqshdagi qism Ma'nosi
Oddiy belgi (a, 7, -) O'zini bildiradi
Maxsus belgi (`. ^ $ * + ? { } [ ] \ ( )`)
\ + belgi Ekranlash yoki maxsus ketma-ketlik

2.2. Beshta asosiy funksiya

Funksiya Qayerda qidiradi Natija
re.search(p, s) Satrning istalgan joyida, birinchisi Match yoki None
re.match(p, s) Faqat boshidan Match yoki None
re.fullmatch(p, s) Butun satr mos kelishi kerak Match yoki None
re.findall(p, s) Hammasi list[str]
re.finditer(p, s) Hammasi, dangasa Match iteratori

Tekshirish (validatsiya) uchun — fullmatch. match faqat boshini tekshiradi: re.match(r"\d+", "123abc") muvaffaqiyatli!

python
if (m := re.search(naqsh, matn)) is not None:
    print(m.group())

2.3. Nega r"..." majburiy

Python satrida \ o'zi maxsus (4.10-dars). Regex'da ham. Ikki qatlam to'qnashadi:

Yozuv Python ko'radi Regex ko'radi
"\b" Backspace belgisi (1 belgi) Backspace — so'z chegarasi emas
r"\b" \ va b (2 belgi) So'z chegarasi
"\\b" \ va b So'z chegarasi (lekin o'qish qiyin)
python
re.findall("\bol\b", "ol olma")    # [] — jim xato!
re.findall(r"\bol\b", "ol olma")   # ['ol']

Qoida: naqshni doim r"..." bilan yozing.

2.4. Ekranlash

Maxsus belgini oddiy belgi sifatida qidirish uchun oldiga \ qo'yiladi:

python
re.search(r"1\+1", "1+1=2")        # '+' — oddiy belgi
re.escape("1+1=2? (ha)")           # '1\\+1=2\\?\\ \\(ha\\)'

Foydalanuvchi kiritgan matnni naqsh ichiga qo'yayotganda har doim re.escape — aks holda . yoki ( naqshni buzadi yoki kutilmagan narsaga mos keladi.

2.5. Belgilar sinflari

Yozuv Ma'nosi
. Istalgan belgi, \n dan tashqari
[aeiou] Shu belgilardan biri
[a-z0-9] Oraliqlar
[^aeiou] Shulardan boshqa istalgan belgi
\d / \D Raqam / raqam emas
\w / \W "So'z belgisi" (harf, raqam, _) / emas
\s / \S Bo'shliq (' ', \t, \n, ...) / emas

Unicode tuzog'i. Python 3'da str naqshlar sukut bo'yicha Unicode rejimida:

Yozuv Sukut (Unicode) re.ASCII bilan
\d 5, arabcha ٣, hindcha ७ Faqat 0-9
\w café, тил, oʻzbek Faqat [a-zA-Z0-9_]
\s Unicode bo'shliqlari ham Faqat ASCII bo'shliqlar

Qiymat aniq 0-9 bo'lishi kerak bo'lsa (karta raqami, PIN, yosh) — [0-9] yoki re.ASCII.

O'zbek matni uchun muhim:

Yozuv \w ga kiradimi
oʻ (U+02BB, rasmiy belgi) Harf (Unicode kategoriyasi Lm)
o' (oddiy apostrof ') Tinish belgisi
o‘ (U+2018, chap tirnoq) Tinish belgisi

re modulida \p{L} (Unicode kategoriyasi) yo'q — re.error beradi. "Faqat harflar" uchun [^\W\d_] ishlatiladi. To'liq Unicode kategoriyalari kerak bo'lsa — tashqi regex kutubxonasi.

2.6. Miqdorlar

Yozuv Necha marta
* 0 yoki ko'p
+ 1 yoki ko'p
? 0 yoki 1
{3} Aynan 3
{2,5} 2 dan 5 gacha
{2,} Kamida 2

Ochko'z va dangasa:

Ochko'z Dangasa Farqi
.* .*? Eng uzun / eng qisqa moslik
.+ .+?
{2,5} {2,5}?
python
re.findall(r"<.+>",  "<b>qalin</b>")   # ['<b>qalin</b>']  — ochko'z
re.findall(r"<.+?>", "<b>qalin</b>")   # ['<b>', '</b>']   — dangasa

* bo'sh moslikka ham mos keladi: re.findall(r"x*", "axxb") → ['', 'xx', '', ''].

2.7. Langarlar

Langar belgi emas, joyni bildiradi.

Yozuv Joy
^ Satr boshi (MULTILINE da — har qator boshi)
$ Satr oxiri yoki oxirgi \n oldi
\A Faqat satr boshi
\Z Faqat satr oxiri
\b So'z chegarasi
\B So'z chegarasi emas

$ oxirgi \n dan oldin ham mos keladi: "abc\n" da $ 3-pozitsiyada, \Z esa 4-pozitsiyada.

2.8. Muqobillar va bayroqlar

| — "yoki". Chapdan o'ngga tekshiriladi va birinchi mos kelgani olinadi:

python
re.findall(r"kot|kotlin", "kotlin")    # ['kot']
re.findall(r"kotlin|kot", "kotlin")    # ['kotlin']

Bayroqlar:

Bayroq Qisqa Ichki yozuv Ta'siri
re.IGNORECASE re.I (?i) Katta-kichik harf farqsiz
re.MULTILINE re.M (?m) ^/$ har qatorda
re.DOTALL re.S (?s) . \n ga ham mos
re.VERBOSE re.X (?x) Bo'shliq va # izohlar
re.ASCII re.A (?a) \d\w\s faqat ASCII

Bir nechtasi: re.I | re.M.

2.9. re.compile va Match

python
TELEFON = re.compile(r"\+998[0-9]{9}")
TELEFON.search(matn); TELEFON.findall(matn)
Fakt Izoh
Modul funksiyalari ham kompilyatsiya qiladi Ichki keshda saqlanadi (512 tagacha)
compile ning foydasi Nom beradi, bayroqlarni bog'laydi, qayta ishlatiladi
Xato naqsh re.PatternError (3.13+; eski nomi re.error)

Match obyekti:

Metod Natija
m.group() Mos kelgan matn
m.start(), m.end(), m.span() Pozitsiyalar
bool(m) Doim True

Guruhlar (group(1), nomli guruhlar) — keyingi darsda.


3. Tez ma'lumotnoma

python
import re

re.search(r"\d+", s)            # birinchi moslik yoki None
re.fullmatch(r"[0-9]{4}", s)    # butun satr — validatsiya
re.findall(r"\w+", s)           # hammasi, ro'yxat
re.finditer(r"\w+", s)          # hammasi, Match lar
re.escape(foydalanuvchi_matni)  # naqsh ichiga xavfsiz qo'yish
NAQSH = re.compile(r"...", re.I | re.X)

Qoidalar

naqsh doim r"..."
validatsiya — fullmatch
aniq 0-9 kerak — [0-9] yoki re.ASCII
foydalanuvchi matni naqshda — re.escape
.* ochko'z — kerak bo'lsa .*?

4. Batafsil misollar

Misol 1 — Asosiy funksiyalar va Match

python
"""search, match, fullmatch farqi; findall va finditer; Match obyekti; xom satr tuzog'i; compile va xato naqsh."""

import re

MATN = "Buyurtma 4521: 3 ta kitob, 12 ta daftar. Jami 185000 so'm."


def main() -> None:
    print("=== 1. search, match, fullmatch ===")
    for funksiya in (re.search, re.match, re.fullmatch):
        for satr in ("4521", "4521-sonli", "buyurtma 4521"):
            m = funksiya(r"\d+", satr)
            natija = repr(m.group()) if m else "None"
            print(f"  {funksiya.__name__:9} {satr!r:16} → {natija}")
    print("  ⭐ validatsiya uchun faqat fullmatch ishonchli")

    print("\n=== 2. findall va finditer ===")
    print(f"  findall:  {re.findall(r'\d+', MATN)}")
    for m in re.finditer(r"\d+", MATN):
        print(f"  finditer: {m.group():>6}  span={m.span()}")

    print("\n=== 3. Match obyekti ===")
    m = re.search(r"\d+", MATN)
    assert m is not None
    print(f"  {m!r}")
    print(f"  group()={m.group()!r}, start()={m.start()}, end()={m.end()}")
    print(f"  kesma bilan bir xil: {MATN[m.start():m.end()] == m.group()}")
    print(f"  bool(m): {bool(m)}, topilmasa: {re.search(r'xyz', MATN)}")

    print("\n=== 4. ⚠️ Xom satr tuzog'i ===")
    print(f"  '\\b' uzunligi: {len('\b')} (backspace), r'\\b' uzunligi: {len(r'\b')}")
    print(f"  oddiy satr naqsh: {re.findall('\bta\b', MATN)}")
    print(f"  xom satr naqsh:   {re.findall(r'\bta\b', MATN)}")

    print("\n=== 5. compile va xato naqsh ===")
    SON = re.compile(r"\d+")
    print(f"  turi: {type(SON).__name__}, naqsh: {SON.pattern!r}")
    print(f"  SON.findall: {SON.findall('7 va 42')}")
    try:
        re.compile(r"[0-9")
    except re.error as xato:
        print(f"  {type(xato).__name__}: {xato.msg} (pozitsiya {xato.pos})")
        print(f"  re.error — PatternError ning eski nomi: {re.error is re.PatternError}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. search, match, fullmatch ===
  search    '4521'           → '4521'
  search    '4521-sonli'     → '4521'
  search    'buyurtma 4521'  → '4521'
  match     '4521'           → '4521'
  match     '4521-sonli'     → '4521'
  match     'buyurtma 4521'  → None
  fullmatch '4521'           → '4521'
  fullmatch '4521-sonli'     → None
  fullmatch 'buyurtma 4521'  → None
  ⭐ validatsiya uchun faqat fullmatch ishonchli

=== 2. findall va finditer ===
  findall:  ['4521', '3', '12', '185000']
  finditer:   4521  span=(9, 13)
  finditer:      3  span=(15, 16)
  finditer:     12  span=(27, 29)
  finditer: 185000  span=(46, 52)

=== 3. Match obyekti ===
  <re.Match object; span=(9, 13), match='4521'>
  group()='4521', start()=9, end()=13
  kesma bilan bir xil: True
  bool(m): True, topilmasa: None

=== 4. ⚠️ Xom satr tuzog'i ===
  '\b' uzunligi: 1 (backspace), r'\b' uzunligi: 2
  oddiy satr naqsh: []
  xom satr naqsh:   ['ta', 'ta']

=== 5. compile va xato naqsh ===
  turi: Pattern, naqsh: '\\d+'
  SON.findall: ['7', '42']
  PatternError: unterminated character set (pozitsiya 0)
  re.error — PatternError ning eski nomi: True

Nima ko'rsatdi: 2.2, 2.3, 2.9-bo'limlar.

Misol 2 — Belgilar sinflari va Unicode

python
r"""[...] sinflari; \d \w \s; Unicode va ASCII rejim; o'zbek apostroflari; \p{L} yo'qligi va [^\W\d_]; re.escape."""

import re
import unicodedata


def main() -> None:
    print("=== 1. Sinflar ===")
    matn = "Dasturlash 2026-yil, narxi $49.99!"
    for naqsh in (r"[aeiou]", r"[A-Z]", r"[0-9]+", r"[^\w\s]", r"[.$]"):
        print(f"  {naqsh:10} → {re.findall(naqsh, matn)}")

    print("\n=== 2. ⚠️ \\d sukut bo'yicha Unicode ===")
    yoshlar = ["25", "٢٥", "२५", "25a"]
    for yosh in yoshlar:
        unicode_rejim = bool(re.fullmatch(r"\d+", yosh))
        ascii_rejim = bool(re.fullmatch(r"\d+", yosh, re.ASCII))
        oraliq = bool(re.fullmatch(r"[0-9]+", yosh))
        print(f"  {yosh!r:6} \\d+={unicode_rejim!s:5}  ASCII={ascii_rejim!s:5}  [0-9]+={oraliq}")
    print(f"  int('٢٥') = {int('٢٥')}  ← Python ularni son deb biladi")

    print("\n=== 3. ⚠️ O'zbek apostroflari va \\w ===")
    variantlar = {"o'zbek": "'", "oʻzbek": "ʻ", "o‘zbek": "‘"}
    for soz, belgi in variantlar.items():
        nom = unicodedata.name(belgi)
        kategoriya = unicodedata.category(belgi)
        print(f"  {soz:8} {nom:32} [{kategoriya}] \\w+ → {re.findall(r'\w+', soz)}")
    print("  ⭐ faqat U+02BB (rasmiy o'zbek belgisi) harf hisoblanadi")

    print("\n=== 4. Faqat harflar: \\p{L} o'rniga ===")
    try:
        re.compile(r"\p{L}+")
    except re.error as xato:
        print(f"  \\p{{L}} → {type(xato).__name__}: {xato.msg}")
    matn = "Oʻzbekiston 2026 café_bar тил"
    print(f"  \\w+       → {re.findall(r'\w+', matn)}")
    print(f"  [^\\W\\d_]+ → {re.findall(r'[^\W\d_]+', matn)}")

    print("\n=== 5. \\s — bo'shliqlar ===")
    matn = "a b\tc\nd\u00a0e"
    print(f"  \\s ga mos keladiganlar: {[hex(ord(b)) for b in re.findall(r'\s', matn)]}")
    print(f"  ASCII rejimda:           {[hex(ord(b)) for b in re.findall(r'\s', matn, re.ASCII)]}")
    print("  ⭐ 0xa0 — bo'linmas bo'shliq (veb sahifalardan nusxalanganda ko'p uchraydi)")

    print("\n=== 6. re.escape ===")
    qidiruv = "narxi $49.99"
    xavfli = re.findall(qidiruv, "narxi $49.99 va narxi 49x99")
    xavfsiz = re.findall(re.escape(qidiruv), "narxi $49.99 va narxi 49x99")
    print(f"  re.escape natijasi: {re.escape(qidiruv)!r}")
    print(f"  ekranlanmagan:  {xavfli}  ← '$' — satr oxiri, '.' — istalgan belgi")
    print(f"  ekranlangan:    {xavfsiz}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Sinflar ===
  [aeiou]    → ['a', 'u', 'a', 'i', 'a', 'i']
  [A-Z]      → ['D']
  [0-9]+     → ['2026', '49', '99']
  [^\w\s]    → ['-', ',', '$', '.', '!']
  [.$]       → ['$', '.']

=== 2. ⚠️ \d sukut bo'yicha Unicode ===
  '25'   \d+=True   ASCII=True   [0-9]+=True
  '٢٥'   \d+=True   ASCII=False  [0-9]+=False
  '२५'   \d+=True   ASCII=False  [0-9]+=False
  '25a'  \d+=False  ASCII=False  [0-9]+=False
  int('٢٥') = 25  ← Python ularni son deb biladi

=== 3. ⚠️ O'zbek apostroflari va \w ===
  o'zbek   APOSTROPHE                       [Po] \w+ → ['o', 'zbek']
  oʻzbek   MODIFIER LETTER TURNED COMMA     [Lm] \w+ → ['oʻzbek']
  o‘zbek   LEFT SINGLE QUOTATION MARK       [Pi] \w+ → ['o', 'zbek']
  ⭐ faqat U+02BB (rasmiy o'zbek belgisi) harf hisoblanadi

=== 4. Faqat harflar: \p{L} o'rniga ===
  \p{L} → PatternError: bad escape \p
  \w+       → ['Oʻzbekiston', '2026', 'café_bar', 'тил']
  [^\W\d_]+ → ['Oʻzbekiston', 'café', 'bar', 'тил']

=== 5. \s — bo'shliqlar ===
  \s ga mos keladiganlar: ['0x20', '0x9', '0xa', '0xa0']
  ASCII rejimda:           ['0x20', '0x9', '0xa']
  ⭐ 0xa0 — bo'linmas bo'shliq (veb sahifalardan nusxalanganda ko'p uchraydi)

=== 6. re.escape ===
  re.escape natijasi: 'narxi\\ \\$49\\.99'
  ekranlanmagan:  []  ← '$' — satr oxiri, '.' — istalgan belgi
  ekranlangan:    ['narxi $49.99']

Nima ko'rsatdi: 2.4, 2.5-bo'limlar.

Misol 3 — Miqdorlar, langarlar, muqobillar, bayroqlar

python
r"""Miqdorlar; ochko'z va dangasa; bo'sh moslik; ^ $ \A \Z \b; | tartibi; MULTILINE, DOTALL, IGNORECASE, VERBOSE."""

import re


def main() -> None:
    print("=== 1. Miqdorlar ===")
    for naqsh in (r"colou?r", r"\d{3}", r"\d{2,3}", r"\d{2,}", r"go+l"):
        print(f"  {naqsh:9} → {re.findall(naqsh, 'color colour 12345 7 gol gooool gl')}")

    print("\n=== 2. Ochko'z va dangasa ===")
    html = '<a href="/bosh">Bosh</a> | <a href="/kurs">Kurs</a>'
    print(f"  <.+>   → {re.findall(r'<.+>', html)}")
    print(f"  <.+?>  → {re.findall(r'<.+?>', html)}")
    print(f"  \"(.*)\"  ochko'z uzunligi: {len(re.search(r'\".*\"', html).group())}")
    print(f"  \"(.*?)\" dangasa:         {re.search(r'\".*?\"', html).group()}")

    print("\n=== 3. ⚠️ Bo'sh moslik ===")
    print(f"  x* 'axxb' da: {re.findall(r'x*', 'axxb')}")
    print(f"  x+ 'axxb' da: {re.findall(r'x+', 'axxb')}")

    print("\n=== 4. Langarlar ===")
    matn = "ol olma bol ol."
    print(f"  ol      → {len(re.findall(r'ol', matn))} ta")
    print(f"  \\bol\\b  → {len(re.findall(r'\bol\b', matn))} ta (alohida so'z)")
    print(f"  \\Bol\\b  → {re.findall(r'\Bol\b', matn)} (so'z oxirida)")
    print(f"  '$' 'abc\\n' da pozitsiya: {re.search(r'$', 'abc\n').start()}")
    print(f"  '\\Z' 'abc\\n' da pozitsiya: {re.search(r'\Z', 'abc\n').start()}")
    print(f"  ⚠️ fullmatch(r'\\d+$') ham '123\\n' ni o'tkazmaydi: {re.fullmatch(r'\d+$', '123\n')}")
    print(f"  lekin match(r'\\d+$') o'tkazadi:                  {bool(re.match(r'\d+$', '123\n'))}")

    print("\n=== 5. Muqobillar tartibi ===")
    print(f"  kot|kotlin → {re.findall(r'kot|kotlin', 'kotlin')}")
    print(f"  kotlin|kot → {re.findall(r'kotlin|kot', 'kotlin')}")
    print("  ⭐ uzunroq muqobilni oldinga qo'ying")

    print("\n=== 6. Bayroqlar ===")
    jurnal = "XATO: disk\nogoh: xotira\nxato: tarmoq"
    print(f"  ^xato               → {re.findall(r'^xato', jurnal)}")
    print(f"  ^xato + I           → {re.findall(r'^xato', jurnal, re.I)}")
    print(f"  ^xato: \\w+ + I + M  → {re.findall(r'^xato: \w+', jurnal, re.I | re.M)}")
    print(f"  (?im) ichki yozuv   → {re.findall(r'(?im)^xato: \w+', jurnal)}")
    print(f"  a.b  → {re.findall(r'a.b', 'a' + chr(10) + 'b')},  DOTALL bilan → {len(re.findall(r'a.b', 'a' + chr(10) + 'b', re.S))} ta")

    print("\n=== 7. VERBOSE — o'qiladigan naqsh ===")
    SANA = re.compile(r"""
        \b
        [0-9]{4}        # yil
        -
        (?:0[1-9]|1[0-2])  # oy: 01-12
        -
        (?:0[1-9]|[12][0-9]|3[01])  # kun: 01-31
        \b
    """, re.VERBOSE)
    print(f"  {SANA.findall('2026-09-17, 2026-13-01, 2026-02-30, 26-09-17')}")
    print("  ⚠️ 2026-02-30 o'tdi — regex taqvimni bilmaydi (15.4-dars: datetime)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Miqdorlar ===
  colou?r   → ['color', 'colour']
  \d{3}     → ['123']
  \d{2,3}   → ['123', '45']
  \d{2,}    → ['12345']
  go+l      → ['gol', 'gooool']

=== 2. Ochko'z va dangasa ===
  <.+>   → ['<a href="/bosh">Bosh</a> | <a href="/kurs">Kurs</a>']
  <.+?>  → ['<a href="/bosh">', '</a>', '<a href="/kurs">', '</a>']
  "(.*)"  ochko'z uzunligi: 34
  "(.*?)" dangasa:         "/bosh"

=== 3. ⚠️ Bo'sh moslik ===
  x* 'axxb' da: ['', 'xx', '', '']
  x+ 'axxb' da: ['xx']

=== 4. Langarlar ===
  ol      → 4 ta
  \bol\b  → 2 ta (alohida so'z)
  \Bol\b  → ['ol'] (so'z oxirida)
  '$' 'abc\n' da pozitsiya: 3
  '\Z' 'abc\n' da pozitsiya: 4
  ⚠️ fullmatch(r'\d+$') ham '123\n' ni o'tkazmaydi: None
  lekin match(r'\d+$') o'tkazadi:                  True

=== 5. Muqobillar tartibi ===
  kot|kotlin → ['kot']
  kotlin|kot → ['kotlin']
  ⭐ uzunroq muqobilni oldinga qo'ying

=== 6. Bayroqlar ===
  ^xato               → []
  ^xato + I           → ['XATO']
  ^xato: \w+ + I + M  → ['XATO: disk', 'xato: tarmoq']
  (?im) ichki yozuv   → ['XATO: disk', 'xato: tarmoq']
  a.b  → [],  DOTALL bilan → 1 ta

=== 7. VERBOSE — o'qiladigan naqsh ===
  ['2026-09-17', '2026-02-30']
  ⚠️ 2026-02-30 o'tdi — regex taqvimni bilmaydi (15.4-dars: datetime)

Nima ko'rsatdi: 2.6, 2.7, 2.8-bo'limlar.

Misol 4 — Amaliy: ro'yxatdan o'tish formasini tekshirish

Kirishdagi vaziyat: forma maydonlari muntazam ifodalar bilan tekshiriladi. Avval xato qoidalarni ko'rsatamiz va ular qaysi kiritishlarda yanglishishini sanaymiz, keyin tuzatilgan qoidalar bilan takrorlaymiz. Har kiritish uchun "to'g'ri javob" oldindan belgilangan — shuning uchun qoidalarni sinov jadvali bilan baholash mumkin.

python
"""Forma validatsiyasi: xato qoidalar va tuzatilganlari; sinov jadvali bilan baholash; o'zbek ismlari, raqamlar, telefon, login."""

import re
import unicodedata

XATO_QOIDALAR = {
    "ism": re.compile(r"^\w+$"),
    "yosh": re.compile(r"\d+"),
    "telefon": re.compile(r"\+998\d{9}"),
    "login": re.compile(r"[a-z0-9_]{3,16}"),
}

ISM_HARFI = r"[^\W\d_]"
TOGRI_QOIDALAR = {
    "ism": re.compile(rf"{ISM_HARFI}+(?:[ʻ'‘`’]{ISM_HARFI}+)*(?:-{ISM_HARFI}+)?"),
    "yosh": re.compile(r"[1-9][0-9]?|1[01][0-9]"),
    "telefon": re.compile(r"\+998[0-9]{9}"),
    "login": re.compile(r"[a-z][a-z0-9_]{2,15}", re.ASCII),
}

# (maydon, kiritish, to'g'ri qabul qilinishi kerakmi)
SINOVLAR = [
    ("ism", "Aziza", True),
    ("ism", "Oʻgʻiloy", True),
    ("ism", "O'g'iloy", True),
    ("ism", "O‘g‘iloy", True),
    ("ism", "Anna-Mariya", True),
    ("ism", "Ali_2", False),
    ("ism", "Ali\n", False),
    ("yosh", "25", True),
    ("yosh", "٢٥", False),
    ("yosh", "25 yosh", False),
    ("yosh", "0", False),
    ("yosh", "119", True),
    ("telefon", "+998901234567", True),
    ("telefon", "+9989012345678", False),
    ("telefon", "tel: +998901234567", False),
    ("telefon", "+998٩٠١٢٣٤٥٦٧", False),
    ("login", "aziz_99", True),
    ("login", "99aziz", False),
    ("login", "az", False),
    ("login", "aziz!!", False),
]


def tekshir(qoidalar: dict[str, re.Pattern[str]], maydon: str, qiymat: str, qat_iy: bool) -> bool:
    naqsh = qoidalar[maydon]
    if qat_iy:
        qiymat = unicodedata.normalize("NFC", qiymat)
        return naqsh.fullmatch(qiymat) is not None
    return naqsh.match(qiymat) is not None


def baholash(nom: str, qoidalar: dict[str, re.Pattern[str]], qat_iy: bool) -> list[str]:
    xatolar = []
    for maydon, qiymat, kutilgan in SINOVLAR:
        if tekshir(qoidalar, maydon, qiymat, qat_iy) != kutilgan:
            holat = "o'tkazib yubordi" if not kutilgan else "rad etdi"
            xatolar.append(f"{maydon:8} {qiymat!r:24} → {holat}")
    print(f"  {nom}: {len(SINOVLAR) - len(xatolar)}/{len(SINOVLAR)} to'g'ri")
    return xatolar


def main() -> None:
    print("=== 1. Xato qoidalar (match, \\w, \\d, langarlarsiz) ===")
    for xato in baholash("xato qoidalar", XATO_QOIDALAR, qat_iy=False):
        print(f"    ❌ {xato}")

    print("\n=== 2. Tuzatilgan qoidalar (fullmatch, [0-9], ASCII, apostroflar) ===")
    xatolar = baholash("tuzatilgan", TOGRI_QOIDALAR, qat_iy=True)
    for xato in xatolar:
        print(f"    ❌ {xato}")
    print(f"  hamma sinov o'tdi: {xatolar == []}")

    print("\n=== 3. Nima o'zgardi ===")
    print("  match → fullmatch:     'tel: ...', '25 yosh', 'aziz!!' endi rad etiladi")
    print("  \\d → [0-9]:            arabcha raqamlar rad etiladi")
    print("  \\w → [^\\W\\d_]:         ismda '_' va raqam rad etiladi")
    print("  apostrof variantlari:  O'g'iloy, Oʻgʻiloy, O‘g‘iloy — hammasi qabul")
    print("  re.ASCII (login):      faqat lotin harflari")

    print("\n=== 4. ⚠️ Regex nimani tekshirmaydi ===")
    print("  telefon raqami haqiqatan mavjudmi — yo'q (SMS kod kerak)")
    print("  yosh mantiqiymi (ro'yxatdan o'tish sanasiga nisbatan) — yo'q")
    print("  ⭐ regex — shakl tekshiruvi; ma'no tekshiruvi — alohida qatlam (13.8-dars)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Xato qoidalar (match, \w, \d, langarlarsiz) ===
  xato qoidalar: 8/20 to'g'ri
    ❌ ism      "O'g'iloy"               → rad etdi
    ❌ ism      'O‘g‘iloy'               → rad etdi
    ❌ ism      'Anna-Mariya'            → rad etdi
    ❌ ism      'Ali_2'                  → o'tkazib yubordi
    ❌ ism      'Ali\n'                  → o'tkazib yubordi
    ❌ yosh     '٢٥'                     → o'tkazib yubordi
    ❌ yosh     '25 yosh'                → o'tkazib yubordi
    ❌ yosh     '0'                      → o'tkazib yubordi
    ❌ telefon  '+9989012345678'         → o'tkazib yubordi
    ❌ telefon  '+998٩٠١٢٣٤٥٦٧'          → o'tkazib yubordi
    ❌ login    '99aziz'                 → o'tkazib yubordi
    ❌ login    'aziz!!'                 → o'tkazib yubordi

=== 2. Tuzatilgan qoidalar (fullmatch, [0-9], ASCII, apostroflar) ===
  tuzatilgan: 20/20 to'g'ri
  hamma sinov o'tdi: True

=== 3. Nima o'zgardi ===
  match → fullmatch:     'tel: ...', '25 yosh', 'aziz!!' endi rad etiladi
  \d → [0-9]:            arabcha raqamlar rad etiladi
  \w → [^\W\d_]:         ismda '_' va raqam rad etiladi
  apostrof variantlari:  O'g'iloy, Oʻgʻiloy, O‘g‘iloy — hammasi qabul
  re.ASCII (login):      faqat lotin harflari

=== 4. ⚠️ Regex nimani tekshirmaydi ===
  telefon raqami haqiqatan mavjudmi — yo'q (SMS kod kerak)
  yosh mantiqiymi (ro'yxatdan o'tish sanasiga nisbatan) — yo'q
  ⭐ regex — shakl tekshiruvi; ma'no tekshiruvi — alohida qatlam (13.8-dars)

Nima ko'rsatdi: 2.2, 2.5, 2.6, 2.7-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"re.match butun satrni tekshiradi" Faqat boshini; butun satr — fullmatch
"\d — 0-9" Sukut bo'yicha har qanday Unicode raqam
"\w — lotin harflari" Unicode harflari, raqamlar va _
"o'zbek — bitta \w+ so'z" Oddiy apostrof harf emas
""\b" va r"\b" bir xil" Birinchisi — backspace belgisi
". istalgan belgi" \n dan tashqari (DOTALL siz)
"$ — satrning eng oxiri" Oxirgi \n oldida ham mos keladi
"re da \p{L} bor" Yo'q — [^\W\d_] yoki regex kutubxonasi

6. Keng tarqalgan xatolar va yechimlari

1. Oddiy satr naqsh

python
re.findall("\bso'z\b", matn)       # ❌ backspace
re.findall(r"\bso'z\b", matn)      # ✅

2. Validatsiyada match yoki search

python
if re.match(r"\d+", yosh): ...     # ❌ '25abc' o'tadi
if re.fullmatch(r"[0-9]+", yosh): ...  # ✅

3. Foydalanuvchi matni ekranlanmagan

python
re.search(qidiruv, matn)           # ❌ 'c++' → xato naqsh
re.search(re.escape(qidiruv), matn)  # ✅

4. Ochko'z .*

python
re.findall(r'"(.*)"', matn)        # ❌ birinchi va oxirgi qo'shtirnoq orasini oladi
re.findall(r'"(.*?)"', matn)       # ✅ yoki [^"]*

5. Muqobillar tartibi

python
r"kot|kotlin"                      # ❌ 'kotlin' da 'kot'
r"kotlin|kot"                      # ✅

6. Topilmaganini tekshirmaslik

python
re.search(naqsh, matn).group()     # ❌ AttributeError: 'NoneType'
if (m := re.search(naqsh, matn)): m.group()  # ✅

7. $ bilan qator oxirini tekshirish

python
re.match(r"[0-9]+$", "123\n")      # ⚠️ o'tadi
re.fullmatch(r"[0-9]+", "123\n")   # ✅ o'tmaydi

8. HTML/JSON ni regex bilan tahlil qilish

python
re.findall(r"<div>(.*?)</div>", html)  # ⚠️ ichma-ich teglar buziladi
# ✅ html.parser, BeautifulSoup, json (16-qism)

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 4-qism (o'tilgan): satr metodlari, xom satrlar, Unicode
  • 13.8-dars (o'tilgan): pydantic da pattern= bilan validatsiya
  • 15.2-dars: guruhlar, sub, split
  • 15.3-dars: amaliy naqshlar, lookahead, ishlash tezligi
  • 16-qism: matn va CSV fayllarni tozalash
  • 17-qism: testlarda chiqishni tekshirish
  • 20.4-dars: route va parametrlar
  • 24-qism: ma'lumotlarni tozalash (pandas.str.extract)

8. Eng yaxshi amaliyotlar

  1. Naqshni doim r"..." bilan yozing.

  2. Validatsiya — fullmatch.

  3. Aniq ASCII kerak bo'lsa — [0-9], re.ASCII.

  4. Foydalanuvchi matnini re.escape qiling.

  5. Murakkab naqshlarni re.VERBOSE va izohlar bilan yozing.

  6. Tez-tez ishlatiladigan naqshga nom bering — TELEFON = re.compile(...).

  7. Naqshni sinov jadvali bilan tekshiring — "o'tishi kerak" va "o'tmasligi kerak" misollar.

  8. Regex hamma narsaga javob emas: oddiy holatlarda startswith, in, isdigit; tuzilgan formatlarda — parser.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import re
1.  print(re.findall(r"\d+", "a1b22c333"))
2.  print(re.match(r"\d+", "abc123"))
3.  print(re.search(r"\d+", "abc123").group())
4.  print(bool(re.fullmatch(r"\d+", "123abc")))
5.  print(re.findall(r"a.c", "abc a\nc aXc"))
6.  print(re.findall(r"<.*?>", "<p><b>"))
7.  print(re.findall(r"\bis\b", "this is his island"))
8.  print(re.findall(r"[^aeiou]", "audio"))
9.  print(len("\n"), len(r"\n"))
10. print(re.findall(r"\w+", "o'rik"))
11. print(bool(re.fullmatch(r"\d", "٣")), bool(re.fullmatch(r"[0-9]", "٣")))
12. print(re.escape("a.b"))
Javoblar
  1. ['1', '22', '333']
  2. None — match faqat boshidan
  3. 123
  4. False
  5. ['abc', 'aXc'] — . \n ga mos kelmaydi
  6. ['<p>', '<b>']
  7. ['is'] — this, his, island ichidagisi so'z chegarasida emas
  8. ['d']
  9. 1 2
  10. ['o', 'rik'] — oddiy apostrof harf emas
  11. True False
  12. a\.b

Vazifa 2: Xatolarni tuzating

python
1.  def pochta_indeksimi(s):
        return re.match("\d{6}", s) is not None

2.  def qidir(soz, matn):
        return re.findall(soz, matn)            # soz = "c++"

3.  def sarlavha(html):
        return re.search(r"<title>(.*)</title>", html).group()

4.  def yil(s):
        return re.fullmatch(r"\d{4}", s)         # "٢٠٢٦" ham o'tadi

5.  FAYL = r"rasm|rasmlar"
    re.findall(FAYL, "rasmlar papkasi")
Javoblar
python
1.  def pochta_indeksimi(s):
        return re.fullmatch(r"[0-9]{6}", s) is not None   # r"", fullmatch, [0-9]

2.  def qidir(soz, matn):
        return re.findall(re.escape(soz), matn)

3.  def sarlavha(html):
        m = re.search(r"<title>(.*?)</title>", html, re.S | re.I)
        return m.group() if m else None                   # None tekshiruvi, dangasa

4.  def yil(s):
        return re.fullmatch(r"[0-9]{4}", s)

5.  FAYL = r"rasmlar|rasm"                               # uzunrog'i oldinda

Vazifa 3: Naqsh sinovchisi

naqsh_sinovi(naqsh, otishi_kerak, otmasligi_kerak) funksiyasini yozing:

  1. fullmatch bilan har bir misolni tekshirsin
  2. Xato natijalarni jadvalda ko'rsatsin
  3. Naqsh kompilyatsiya bo'lmasa — PatternError xabari va pozitsiyasini chiqarsin
  4. O'zbek avtomobil raqami (01 A 123 AA, 01 123 AAA) uchun naqsh yozib, 10 ta ijobiy va 10 ta salbiy misol bilan sinang

Vazifa 4: Matn statistikasi

Berilgan o'zbekcha matn uchun:

  1. So'zlar soni — apostrofli so'zlar (o'zbek, g'alaba) bitta so'z hisoblansin
  2. Eng ko'p uchragan 10 so'z (katta-kichik harf farqsiz)
  3. Sonlar va ularning yig'indisi
  4. Gaplar soni (., !, ? bilan tugaydi, lekin 3.14 ichidagi nuqta emas)
  5. Natijani split() asosidagi sodda usul bilan solishtiring

Vazifa 5: Apostrofni me'yorlash

  1. Matndagi o', g' va ularning variantlarini (', ‘, ’, `, ʼ) topsin
  2. Hammasini rasmiy ʻ (U+02BB) ga almashtirsin — faqat o va g dan keyin
  3. sh' kabi tutuq belgisini (ma'no, san'at) ʼ (U+02BC) ga almashtirsin
  4. Almashtirishlar sonini hisoblasin
  5. 20 ta real jumla bilan sinang (almashtirish — keyingi darsdagi re.sub; hozircha finditer va satr yig'ish bilan)

Vazifa 6: Jurnal filtri

Server jurnali (kamida 50 qator) uchun:

  1. ERROR va CRITICAL qatorlarni katta-kichik harf farqsiz toping (MULTILINE)
  2. IP manzillarni ajrating (to'rt qism, har biri 0–255 — faqat shakl)
  3. Vaqt belgilarini (2026-09-17 14:03:22) toping
  4. Bitta naqshni VERBOSE rejimida izohlar bilan yozing
  5. Har naqsh uchun sinov jadvali tuzing

Vazifa 7: O'ylash

Muntazam ifodalar 1950-yillarda matematik Stiven Klini tomonidan formal tillar nazariyasida kiritilgan. Nazariyada "muntazam til"ni qavslar balansini ((()())) tekshira olmaydigan mashina taniydi. Python'dagi re esa backreference (\1) kabi imkoniyatlarga ega. Nega HTML'ni regex bilan tahlil qilish "yomon g'oya" deyiladi va bu nazariya bilan qanday bog'liq?

Javob

Qisqa javob: Nazariy muntazam ifodalar cheklangan xotirali mashina (cheklangan avtomat) bilan tanilanadi — u ichma-ich tuzilmalarni (qavslar, HTML teglari) sanay olmaydi. HTML esa ichma-ich tuzilgan — uni tahlil qilish uchun stek (kontekstsiz grammatika) kerak. Python'ning re i nazariyadan kuchliroq (backreference), lekin baribir ichma-ich tuzilmalar uchun mo'ljallanmagan va bunday naqshlar mo'rt, sekin va xavfli bo'ladi.

1. Nazariya: Xomskiy ierarxiyasi

Til turi Taniydigan mashina Misol
Muntazam Cheklangan avtomat (xotira yo'q) Telefon raqami, sana shakli
Kontekstsiz Stekli avtomat Qavslar balansi, HTML, JSON, Python kodi
Kontekstga bog'liq Chiziqli chegaralangan mashina Ba'zi dasturlash tillari qoidalari
Rekursiv sanaladigan Tyuring mashinasi Istalgan hisoblash

2. Nega qavslarni sanab bo'lmaydi

Cheklangan avtomatning holatlari soni qat'iy, masalan N ta. N+1 ta ochiq qavsdan keyin u nechta ochilganini "eslay" olmaydi — ikki xil chuqurlik bitta holatga tushadi (Dirixle prinsipi). Demak (((...))) ni istalgan chuqurlikda to'g'ri tekshira olmaydi.

3. Python'ning re i nazariyadan kuchli

  • \1 (backreference) — "avval topilgan narsa yana takrorlansin": (\w+) \1 — bu muntazam til emas
  • Lookahead / lookbehind (15.3-dars)
  • Lekin rekursiya yo'q: re da (?R) yo'q (tashqi regex kutubxonasida bor)
  • Shuning uchun re ichma-ich teglarni umumiy holda tahlil qila olmaydi

4. HTML ni regex bilan tahlil qilish muammolari

Muammo Misol
Ichma-ich teglar <div><div>a</div>b</div> — <div>(.*?)</div> birinchi yopilishda to'xtaydi
Atributlar tartibi va qo'shtirnoqlar <a class="x" href='y'>, href=y
Izohlar va <script> <!-- <div> -->, JavaScript ichidagi </div> satri
Buzilgan HTML Brauzerlar tuzatadi, regex esa yo'q
Katastrofik backtracking Murakkab naqsh eksponensial sekinlashadi (15.3-dars)

5. To'g'ri yondashuv

Vazifa Vosita
HTML html.parser, BeautifulSoup, lxml
JSON json (16.2-dars)
Python kodi ast
Qavslar balansi Stek bilan oddiy tsikl
Tokenlar (so'z, son, belgi) Regex — ideal (15.3-dars: tokenizator)

Amaliy qoida: regex leksik darajada (tokenlar, shakllar) juda yaxshi; sintaktik daraja (tuzilma, ichma-ichlik) uchun parser kerak. Ko'p parserlar ichida regex tokenizator ishlaydi.

6. Xulosa

  1. Nazariy muntazam ifodalar xotirasiz mashinaga teng — ichma-ichlikni sanay olmaydi
  2. re backreference bilan kuchliroq, lekin rekursiv tuzilmalar uchun emas
  3. HTML/JSON/kod uchun parser, tokenlar uchun regex
  4. "Regex bilan HTML" — ba'zan kichik bir martalik skriptda ishlaydi, lekin ishonchli tizimda emas

Nimani mustahkamlaydi: 2.1–2.9-bo'limlar.


Xulosa

Bu darsda muntazam ifodalar tilining asoslarini o'rgandik.

Eng muhim uch fikr:

  1. To'g'ri funksiya va xom satr. search istalgan joydan, match faqat boshidan, fullmatch butun satrni tekshiradi — validatsiya uchun faqat fullmatch ishonchli. Naqsh doim r"..." bilan yoziladi: oddiy satrda "\b" backspace belgisiga aylanib, naqsh jimgina hech narsa topmaydi. Foydalanuvchi matni naqshga re.escape orqali qo'yiladi.

  2. \d, \w, \s — Unicode. Sukut bo'yicha \d arabcha va hindcha raqamlarni, \w esa har qanday alifbo harflarini qabul qiladi. Aniq 0-9 kerak bo'lsa — [0-9] yoki re.ASCII. O'zbek matnida faqat rasmiy ʻ (U+02BB) harf hisoblanadi, oddiy ' esa so'zni ikkiga bo'ladi. re da \p{L} yo'q — "faqat harflar" uchun [^\W\d_].

  3. Miqdorlar, langarlar va bayroqlar naqsh ma'nosini tubdan o'zgartiradi. .* ochko'z — eng uzun moslikni oladi, .*? dangasa — eng qisqasini. $ oxirgi \n dan oldin ham mos keladi, | esa birinchi mos kelgan muqobilni oladi. MULTILINE, DOTALL, IGNORECASE va o'qiladigan naqshlar uchun VERBOSE — har kungi vositalar.

Keyingi darsda naqshdan ma'lumot ajratib olishni o'rganamiz: guruhlar, nomli guruhlar, re.sub bilan almashtirish va re.split.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.1-dars: Muntazam ifodalar: asoslar — IlmHamroh