Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Guruhlar
- 2.2. Nomli guruhlar
- 2.3. Ushlamaydigan guruh va findall tuzog'i
- 2.4. Ixtiyoriy guruhlar
- 2.5. Qayta havola
- 2.6. re.sub — almashtirish
- 2.7. Pozitsion count va flags
- 2.8. re.split
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Guruhlar
- Misol 2 — re.sub va subn
- Misol 3 — re.split
- Misol 4 — Amaliy: jurnal tahlilchisi va shaxsiy ma'lumotni yashirish
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
15.2-dars: re: guruh va almashtirish
15-QISM — STANDART KUTUBXONA · 2-dars
1. Kirish va motivatsiya
15.1-darsda naqsh mos keladimi degan savolga javob berdik. Amaliyotda esa bu kam: bizga moslikning ichidagi qismlar kerak.
- Sanadan yil, oy va kunni alohida olish.
- Jurnal qatoridan sana, vaqt, daraja, modul va xabarni ajratish.
17.09.2026ni2026-09-17ga aylantirish.- Matndagi barcha telefon raqamlarini
+998 90 *** ** 67ko'rinishida yashirish.
Bular uchun uchta vosita kerak: guruhlar — naqsh ichidan qism ajratish, re.sub — topilganini almashtirish va re.split — naqsh bo'yicha bo'lish.
Real vaziyat. Jamoa foydalanuvchi matnlaridan shaxsiy ma'lumotni yashirish uchun shunday yozdi:
re.sub(r"\d{9}", "*********", matn, re.IGNORECASE)Kod xatosiz ishladi, testlar o'tdi. Ishlab chiqarishda esa har bir matndagi faqat birinchi ikkita raqam yashirildi, qolganlari jurnallarga ochiq holda tushdi. Sabab: to'rtinchi pozitsion argument — bu flags emas, count, va re.IGNORECASE ning son qiymati 2 ga teng. Bu darsda shunday tuzoqlarni ham ko'ramiz.
Bu darsda:
- Tartib raqamli guruhlar:
group(1),groups() - Nomli guruhlar:
(?P<nom>...),groupdict() - Ushlamaydigan guruh:
(?:...)vafindalltuzog'i - Ixtiyoriy guruhlar va
None - Qayta havola:
\1,(?P=nom) -
re.sub:\1,\g<nom>, funksiya bilan almashtirish,subn,count - Pozitsion
countvaflagstuzog'i re.split: guruhli ajratgich,maxsplit, bo'sh qismlar- Amaliy: jurnal tahlilchisi va shaxsiy ma'lumotni yashirish
2. Nazariya — chuqur tushuntirish
2.1. Guruhlar
Qavs (...) ikki ish qiladi: naqsh qismlarini birlashtiradi (miqdor butun guruhga qo'llanadi) va mos kelgan matnni ushlaydi.
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", "sana: 2026-09-17.")
m.group(0) # '2026-09-17' — butun moslik
m.group(1) # '2026'
m.group(2, 3) # ('09', '17')
m.groups() # ('2026', '09', '17')
m.span(2) # (11, 13)
m[1] # '2026' — qisqa yozuv| Metod | Natija |
|---|---|
m.group(0) / m.group() / m[0] |
Butun moslik |
m.group(n) / m[n] |
n-guruh |
m.groups() |
Hamma guruhlar kortej |
m.start(n), m.end(n), m.span(n) |
Guruh pozitsiyasi |
m.lastindex |
Oxirgi mos kelgan guruh raqami |
Guruhlar ochiluvchi qavs tartibida raqamlanadi: ((a)(b)) da 1 — tashqi, 2 — a, 3 — b.
2.2. Nomli guruhlar
m = re.search(r"(?P<yil>\d{4})-(?P<oy>\d{2})", "2026-09")
m["yil"] # '2026'
m.groupdict() # {'yil': '2026', 'oy': '09'}Ikkitadan ko'p guruh bo'lsa — nomli guruh ishlating: kod o'qiladi va naqshga yangi guruh qo'shilganda raqamlar siljimaydi.
2.3. Ushlamaydigan guruh va findall tuzog'i
(?:...) — birlashtiradi, lekin ushlamaydi.
findall natijasi guruhlar soniga bog'liq:
| Naqshdagi guruhlar | findall qaytaradi |
|---|---|
| 0 ta | Butun moslik satrlari |
| 1 ta | Faqat shu guruh satrlari |
| 2+ ta | Kortejlar ro'yxati |
re.findall(r"(\w+)=(\d+)", "a=1 b=22") # [('a', '1'), ('b', '22')]
re.findall(r"\w+=(\d+)", "a=1 b=22") # ['1', '22'] — butun moslik yo'qoldi!
re.findall(r"(?:\w+)=\d+", "a=1 b=22") # ['a=1', 'b=22'] Guruhni faqat miqdor yoki muqobil uchun ishlatayotgan bo'lsangiz — (?:...).
2.4. Ixtiyoriy guruhlar
Mos kelmagan guruh — None:
m = re.search(r"(\+998)?(\d{9})", "901234567")
m.groups() # (None, '901234567')
m.groups(default="") # ('', '901234567')
m.groupdict(default="-") findall da esa mos kelmagan guruh None emas, bo'sh satr '' bo'ladi.
2.5. Qayta havola
Naqsh ichida avval ushlangan matnni takrorlash:
| Yozuv | Ma'nosi |
|---|---|
\1, \2 |
1-, 2-guruh matni |
(?P=nom) |
Nomli guruh matni |
re.findall(r"\b(\w+) \1\b", "bu bu xato xato emas") # ['bu', 'xato'] — takrorlangan so'zlar
re.search(r"(?P<q>['\"]).*?(?P=q)", "x = 'salom'") # ochilgan qo'shtirnoq bilan yopilgan2.6. re.sub — almashtirish
re.sub(naqsh, almashtirma, matn, count=0, flags=0)Almashtirma satr ichida:
| Yozuv | Ma'nosi |
|---|---|
\1, \2 |
Guruh matni |
\g<1> |
Guruh matni (raqamdan keyin raqam kelsa) |
\g<nom> |
Nomli guruh |
\g<0> |
Butun moslik |
\n, \t |
Yangi qator, tab — almashtirma ichida qayta ishlanadi |
re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3.\2.\1", "2026-09-17") # '17.09.2026'
re.sub(r"(\d)", r"\g<1>0", "a1b2") # 'a10b20' r"\10" — "1-guruh va 0" emas, 10-guruh. Kerakligi — r"\g<1>0".
Funksiya bilan almashtirish — har moslik uchun funksiya chaqiriladi, u Match oladi va satr qaytaradi:
re.sub(r"\d+", lambda m: str(int(m[0]) * 2), "3 olma 12 nok") # '6 olma 24 nok' Funksiya qaytargan satrdagi \ qayta ishlanmaydi — tashqi matnni almashtirma sifatida qo'yishning xavfsiz yo'li.
| Funksiya | Natija |
|---|---|
re.sub(...) |
Yangi satr |
re.subn(...) |
(yangi_satr, almashtirishlar_soni) |
2.7. Pozitsion count va flags
re.sub(naqsh, almashtirma, matn, re.I) # ❌ re.I == 2 → count=2, bayroq YO'Q
re.sub(naqsh, almashtirma, matn, flags=re.I) # ✅| Versiya | Pozitsion count/flags |
|---|---|
| ≤ 3.12 | Jim ishlaydi |
| 3.13+ | DeprecationWarning |
| Kelajakda | Xato bo'ladi |
Xuddi shu tuzoq re.split(naqsh, matn, re.I) da ham bor — u yerda uchinchi argument maxsplit.
Qoida: count, maxsplit va flags ni doim nomi bilan yozing.
2.8. re.split
| Holat | Natija |
|---|---|
| Oddiy naqsh | Ajratgichlar tashlanadi |
| Guruhli naqsh | Ajratgichlar ham natijaga kiradi |
| Boshida/oxirida ajratgich | Bo'sh satr '' |
maxsplit=n |
Ko'pi bilan n marta bo'ladi |
re.split(r"[,;]\s*", "olma, nok;uzum") # ['olma', 'nok', 'uzum']
re.split(r"([,;])", "a,b;c") # ['a', ',', 'b', ';', 'c']
re.split(r"\s+", " a b ") # ['', 'a', 'b', '']str.split() |
re.split(r"\s+", ...) |
|---|---|
| Boshi/oxiridagi bo'shliqni tashlaydi | Bo'sh satr qoldiradi |
| Faqat bitta ajratgich (yoki bo'shliqlar) | Istalgan naqsh |
| Tezroq | Moslashuvchan |
3. Tez ma'lumotnoma
m = re.search(r"(?P<yil>[0-9]{4})-(?P<oy>[0-9]{2})", s)
m["yil"], m.groupdict(), m.groups(default="")
re.findall(r"(?:ab)+", s) # ushlamaydigan guruh
re.sub(r"([0-9]{2})\.([0-9]{2})\.([0-9]{4})", r"\3-\2-\1", s)
re.sub(naqsh, lambda m: m[0].upper(), s, count=1, flags=re.I)
yangi, soni = re.subn(naqsh, "", s)
re.split(r"\s*([,;])\s*", s, maxsplit=2)Qoidalar
2+ guruh — nomli guruhlar
faqat birlashtirish — (?:...)
findall natijasi guruhlar soniga bog'liq
guruhdan keyin raqam — \g<1>0
count, maxsplit, flags — doim nomi bilan
tashqi matn almashtirmada — funksiya orqali4. Batafsil misollar
Misol 1 — Guruhlar
r"""Tartib raqamli va nomli guruhlar; groups va groupdict; (?:...); findall tuzog'i; ixtiyoriy guruh; lastindex; qayta havola."""
import re
def main() -> None:
print("=== 1. Tartib raqamli guruhlar ===")
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", "Hisobot sanasi: 2026-09-17.")
assert m is not None
print(f" group(0)={m.group(0)!r} group(1)={m[1]!r} group(2, 3)={m.group(2, 3)}")
print(f" groups()={m.groups()} span(2)={m.span(2)} lastindex={m.lastindex}")
ichma = re.search(r"((\w+)@(\w+))\.uz", "aloqa: aziz@wisar.uz")
assert ichma is not None
print(f" ichma-ich ((a)(b)) tartibi: {ichma.groups()}")
print("\n=== 2. Nomli guruhlar ===")
SANA = re.compile(r"(?P<kun>\d{2})\.(?P<oy>\d{2})\.(?P<yil>\d{4})")
m = SANA.search("Tug'ilgan: 05.03.1998")
assert m is not None
print(f" m['yil']={m['yil']!r}, groupdict()={m.groupdict()}")
print(f" groupindex (nom → raqam): {dict(SANA.groupindex)}")
print("\n=== 3. ⚠️ findall natijasi guruhlar soniga bog'liq ===")
matn = "host=localhost port=5432 debug=1"
for naqsh in (r"\w+=\w+", r"\w+=(\w+)", r"(\w+)=(\w+)", r"(?:\w+)=\w+"):
print(f" {naqsh:14} → {re.findall(naqsh, matn)}")
print("\n=== 4. Miqdor guruhga qo'llanganda ===")
print(f" (ha)+ → {re.findall(r'(ha)+', 'hahaha hoho ha')} ← faqat oxirgi takror")
print(f" ((?:ha)+) → {re.findall(r'((?:ha)+)', 'hahaha hoho ha')}")
print("\n=== 5. Ixtiyoriy guruhlar ===")
TELEFON = re.compile(r"(\+998)?\s?(\d{2})\s?(\d{3})\s?(\d{2})\s?(\d{2})")
for raqam in ("+998 90 123 45 67", "901234567"):
m = TELEFON.fullmatch(raqam)
assert m is not None
print(f" {raqam!r:21} groups()={m.groups()}")
print(f" {'':21} groups(default='-')[0]={m.groups(default='-')[0]!r}")
print(f" findall da None o'rniga: {re.findall(r'(\+998)?(\d{9})', '901234567')}")
print("\n=== 6. Muqobillar va lastindex ===")
TOKEN = re.compile(r"(?P<son>\d+)|(?P<soz>[^\W\d_]+)|(?P<belgi>[^\w\s])")
for m in TOKEN.finditer("narx 25 so'm!"):
print(f" {m[0]!r:8} lastgroup={m.lastgroup:6} lastindex={m.lastindex}")
print("\n=== 7. Qayta havola ===")
print(f" takror so'zlar: {re.findall(r'\b(\w+) \1\b', 'bu bu matnda xato xato bor bor')}")
iqtibos = re.compile(r"(?P<q>['\"])(?P<ichi>.*?)(?P=q)")
for m in iqtibos.finditer("""a = "o'zbek" b = 'Wisar' c = "yopilmagan'"""):
print(f" qo'shtirnoq={m['q']} ichi={m['ichi']!r}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Tartib raqamli guruhlar ===
group(0)='2026-09-17' group(1)='2026' group(2, 3)=('09', '17')
groups()=('2026', '09', '17') span(2)=(21, 23) lastindex=3
ichma-ich ((a)(b)) tartibi: ('aziz@wisar', 'aziz', 'wisar')
=== 2. Nomli guruhlar ===
m['yil']='1998', groupdict()={'kun': '05', 'oy': '03', 'yil': '1998'}
groupindex (nom → raqam): {'kun': 1, 'oy': 2, 'yil': 3}
=== 3. ⚠️ findall natijasi guruhlar soniga bog'liq ===
\w+=\w+ → ['host=localhost', 'port=5432', 'debug=1']
\w+=(\w+) → ['localhost', '5432', '1']
(\w+)=(\w+) → [('host', 'localhost'), ('port', '5432'), ('debug', '1')]
(?:\w+)=\w+ → ['host=localhost', 'port=5432', 'debug=1']
=== 4. Miqdor guruhga qo'llanganda ===
(ha)+ → ['ha', 'ha'] ← faqat oxirgi takror
((?:ha)+) → ['hahaha', 'ha']
=== 5. Ixtiyoriy guruhlar ===
'+998 90 123 45 67' groups()=('+998', '90', '123', '45', '67')
groups(default='-')[0]='+998'
'901234567' groups()=(None, '90', '123', '45', '67')
groups(default='-')[0]='-'
findall da None o'rniga: [('', '901234567')]
=== 6. Muqobillar va lastindex ===
'narx' lastgroup=soz lastindex=2
'25' lastgroup=son lastindex=1
'so' lastgroup=soz lastindex=2
"'" lastgroup=belgi lastindex=3
'm' lastgroup=soz lastindex=2
'!' lastgroup=belgi lastindex=3
=== 7. Qayta havola ===
takror so'zlar: ['bu', 'xato', 'bor']
qo'shtirnoq=" ichi="o'zbek"
qo'shtirnoq=' ichi='Wisar'Nima ko'rsatdi: 2.1–2.5-bo'limlar.
Misol 2 — re.sub va subn
r"""Almashtirma satrdagi \1 va \g<nom>; \g<1>0; funksiya bilan almashtirish; subn va count; almashtirmadagi escape; pozitsion count tuzog'i."""
import re
import warnings
def main() -> None:
print("=== 1. Guruhlarni qayta tartiblash ===")
print(f" {re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3.\2.\1', 'Sana: 2026-09-17')}")
print(f" {re.sub(r'(?P<kun>\d{2})\.(?P<oy>\d{2})\.(?P<yil>\d{4})', r'\g<yil>-\g<oy>-\g<kun>', '17.09.2026')}")
print(f" {re.sub(r'\b(\w+) \1\b', r'\1', 'bu bu matnda xato xato bor')}")
print(f" \\g<0> — butun moslik: {re.sub(r'\d+', r'[\g<0>]', 'olma 3, nok 12')}")
print("\n=== 2. ⚠️ \\10 va \\g<1>0 ===")
print(f" r'\\g<1>0' → {re.sub(r'(\d)', r'\g<1>0', 'a1b2')}")
try:
re.sub(r"(\d)", r"\10", "a1b2")
except re.error as xato:
print(f" r'\\10' → {type(xato).__name__}: {xato}")
print("\n=== 3. Funksiya bilan almashtirish ===")
narxlar = "Kitob 45000 so'm, daftar 8000 so'm"
print(f" {re.sub(r'\d+', lambda m: f'{int(m[0]) * 1.12:,.0f}'.replace(',', ' '), narxlar)}")
def unvon(m: re.Match[str]) -> str:
soz = m[0]
return soz if soz.lower() in {"va", "bilan", "uchun"} else soz.capitalize()
print(f" {re.sub(r'[^\W\d_]+', unvon, 'python va rust bilan tizim dasturlash')}")
print("\n=== 4. subn va count ===")
matn = "a b c d"
print(f" subn: {re.subn(r'\s+', ' ', matn)}")
print(f" count=2: {re.sub(r'\s+', ' ', matn, count=2)!r}")
print("\n=== 5. ⚠️ Almashtirmadagi \\ belgilari ===")
yol1 = r"C:\new\table"
yol2 = r"C:\Users\aziz"
print(f" asl yo'l: {yol1!r}")
print(f" satr almashtirma: {re.sub(r'YOL', yol1, 'papka: YOL')!r} ← \\n va \\t buzildi")
try:
re.sub(r"YOL", yol2, "papka: YOL")
except re.error as xato:
print(f" {yol2!r} bilan: {type(xato).__name__}: {xato}")
print(f" funksiya almashtirma: {re.sub(r'YOL', lambda m: yol1, 'papka: YOL')!r}")
print(f" funksiya, ikkinchi yo'l: {re.sub(r'YOL', lambda m: yol2, 'papka: YOL')!r}")
print(" ⭐ tashqi matnni almashtirmaga qo'yishda — funksiya")
print("\n=== 6. ⚠️ Pozitsion count tuzog'i ===")
matn = "Raqamlar: 901234567, 911234567, 931234567"
with warnings.catch_warnings(record=True) as ogohlantirishlar:
warnings.simplefilter("always")
xato_natija = re.sub(r"\d{9}", "*********", matn, re.IGNORECASE)
print(f" re.IGNORECASE ning qiymati: {int(re.IGNORECASE)}")
print(f" pozitsion: {xato_natija}")
print(f" ogohlantirish: {ogohlantirishlar[0].category.__name__}: {ogohlantirishlar[0].message}")
print(f" nomli: {re.sub(r'\d{9}', '*********', matn, flags=re.IGNORECASE)}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Guruhlarni qayta tartiblash ===
Sana: 17.09.2026
2026-09-17
bu matnda xato bor
\g<0> — butun moslik: olma [3], nok [12]
=== 2. ⚠️ \10 va \g<1>0 ===
r'\g<1>0' → a10b20
r'\10' → PatternError: invalid group reference 10 at position 1
=== 3. Funksiya bilan almashtirish ===
Kitob 50 400 so'm, daftar 8 960 so'm
Python va Rust bilan Tizim Dasturlash
=== 4. subn va count ===
subn: ('a b c d', 3)
count=2: 'a b c d'
=== 5. ⚠️ Almashtirmadagi \ belgilari ===
asl yo'l: 'C:\\new\\table'
satr almashtirma: 'papka: C:\new\table' ← \n va \t buzildi
'C:\\Users\\aziz' bilan: PatternError: bad escape \U at position 2
funksiya almashtirma: 'papka: C:\\new\\table'
funksiya, ikkinchi yo'l: 'papka: C:\\Users\\aziz'
⭐ tashqi matnni almashtirmaga qo'yishda — funksiya
=== 6. ⚠️ Pozitsion count tuzog'i ===
re.IGNORECASE ning qiymati: 2
pozitsion: Raqamlar: *********, *********, 931234567
ogohlantirish: DeprecationWarning: 'count' is passed as positional argument
nomli: Raqamlar: *********, *********, *********Nima ko'rsatdi: 2.6, 2.7-bo'limlar.
Misol 3 — re.split
r"""Oddiy va guruhli ajratgich; bo'sh qismlar; maxsplit; str.split bilan solishtirish; oddiy tokenizator."""
import re
def main() -> None:
print("=== 1. Bir nechta ajratgich ===")
royxat = "olma, nok;uzum , gilos|anor"
print(f" [,;|]\\s* → {re.split(r'[,;|]\s*', royxat)}")
print(f" \\s*[,;|]\\s* → {re.split(r'\s*[,;|]\s*', royxat)}")
print("\n=== 2. Guruhli ajratgich natijada qoladi ===")
ifoda = "12 + 7*3 - 4 / 2"
print(f" \\s*[-+*/]\\s* → {re.split(r'\s*[-+*/]\s*', ifoda)}")
print(f" \\s*([-+*/])\\s* → {re.split(r'\s*([-+*/])\s*', ifoda)}")
print("\n=== 3. Bo'sh qismlar ===")
print(f" re.split(r'\\s+', ' a b ') → {re.split(r'\s+', ' a b ')}")
print(f" ' a b '.split() → {' a b '.split()}")
print(f" bo'shlarini tashlash: {[q for q in re.split(r'\s+', ' a b ') if q]}")
print(f" bo'sh moslik bilan: {re.split(r'x*', 'axbc')}")
print("\n=== 4. maxsplit ===")
qator = "2026-09-17 14:03:22 ERROR baza: ulanish uzildi: timeout"
sana, vaqt, daraja, xabar = re.split(r"\s+", qator, maxsplit=3)
print(f" daraja={daraja!r}, xabar={xabar!r}")
manba, _, tafsilot = xabar.partition(": ")
print(f" manba={manba!r}, tafsilot={tafsilot!r}")
print("\n=== 5. Tokenizator: split va findall ===")
kod = "narx=(soni*12)+ 5"
print(f" split bilan: {[t for t in re.split(r'\s*([=()*+])\s*', kod) if t]}")
print(f" findall bilan: {re.findall(r'\d+|\w+|[=()*+]', kod)}")
print(" ⭐ tokenlar uchun findall/finditer ko'pincha aniqroq (15.3-dars)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bir nechta ajratgich ===
[,;|]\s* → ['olma', 'nok', 'uzum ', 'gilos', 'anor']
\s*[,;|]\s* → ['olma', 'nok', 'uzum', 'gilos', 'anor']
=== 2. Guruhli ajratgich natijada qoladi ===
\s*[-+*/]\s* → ['12', '7', '3', '4', '2']
\s*([-+*/])\s* → ['12', '+', '7', '*', '3', '-', '4', '/', '2']
=== 3. Bo'sh qismlar ===
re.split(r'\s+', ' a b ') → ['', 'a', 'b', '']
' a b '.split() → ['a', 'b']
bo'shlarini tashlash: ['a', 'b']
bo'sh moslik bilan: ['', 'a', '', 'b', 'c', '']
=== 4. maxsplit ===
daraja='ERROR', xabar='baza: ulanish uzildi: timeout'
manba='baza', tafsilot='ulanish uzildi: timeout'
=== 5. Tokenizator: split va findall ===
split bilan: ['narx', '=', '(', 'soni', '*', '12', ')', '+', '5']
findall bilan: ['narx', '=', '(', 'soni', '*', '12', ')', '+', '5']
⭐ tokenlar uchun findall/finditer ko'pincha aniqroq (15.3-dars)Nima ko'rsatdi: 2.8-bo'lim.
Misol 4 — Amaliy: jurnal tahlilchisi va shaxsiy ma'lumotni yashirish
Kirishdagi vaziyat: xizmat jurnallari tahlil uchun boshqa jamoaga yuboriladi. Avval har qatorni nomli guruhlar bilan tuzilgan yozuvga aylantiramiz, keyin xabarlardagi email, telefon va karta raqamlarini yashiramiz, oxirida statistika chiqaramiz. Yashirish natijasi tekshiriladi: chiqishda birorta ham to'liq shaxsiy ma'lumot qolmasligi kerak.
"""Nomli guruhlar bilan jurnalni tahlil qilish; funksiya bilan yashirish; subn bilan hisoblash; qoldiq tekshiruvi; statistika."""
import re
from collections import Counter
JURNAL = """\
2026-09-17 09:12:03 INFO [auth] kirish: aziz@wisar.uz, tel +998 90 123 45 67
2026-09-17 09:12:09 WARN [pay] karta 8600 1234 5678 9012 rad etildi
2026-09-17 09:13:44 ERROR [pay] to'lov xatosi: user=bek.nazarov@mail.uz summa=125000
2026-09-17 09:14:02 INFO [auth] parol tiklash: +998911234567
buzilgan qator
2026-09-17 09:15:30 ERROR [db] ulanish uzildi (timeout=30s)
"""
QATOR = re.compile(
r"""
(?P<sana>\d{4}-\d{2}-\d{2})\s
(?P<vaqt>\d{2}:\d{2}:\d{2})\s
(?P<daraja>INFO|WARN|ERROR)\s+
\[(?P<modul>\w+)\]\s
(?P<xabar>.*)
""",
re.VERBOSE,
)
EMAIL = re.compile(r"(?P<nom>[\w.]+)@(?P<domen>[\w.]+\.[a-z]{2,})")
TELEFON = re.compile(r"\+998\s?(?P<kod>[0-9]{2})\s?[0-9]{3}\s?[0-9]{2}\s?(?P<oxiri>[0-9]{2})")
KARTA = re.compile(r"\b[0-9]{4}(?:\s?[0-9]{4}){2}\s?(?P<oxiri>[0-9]{4})\b")
def email_yashir(m: re.Match[str]) -> str:
return f"{m['nom'][0]}***@{m['domen']}"
def yashir(xabar: str) -> tuple[str, Counter[str]]:
hisob: Counter[str] = Counter()
for nom, naqsh, almashtirma in (
("karta", KARTA, r"**** **** **** \g<oxiri>"),
("email", EMAIL, email_yashir),
("telefon", TELEFON, r"+998 \g<kod> *** ** \g<oxiri>"),
):
xabar, soni = naqsh.subn(almashtirma, xabar)
hisob[nom] += soni
return xabar, hisob
def main() -> None:
yozuvlar, buzilganlar = [], []
for raqam, qator in enumerate(JURNAL.splitlines(), start=1):
if (m := QATOR.fullmatch(qator)) is None:
buzilganlar.append(raqam)
continue
yozuvlar.append(m.groupdict())
print("=== 1. Tahlil ===")
print(f" tuzilgan yozuvlar: {len(yozuvlar)}, buzilgan qatorlar: {buzilganlar}")
birinchi = yozuvlar[0]
print(f" birinchi yozuv kalitlari: {list(birinchi)}")
print(f" daraja={birinchi['daraja']!r}, modul={birinchi['modul']!r}")
print("\n=== 2. Yashirish ===")
jami: Counter[str] = Counter()
for yozuv in yozuvlar:
yozuv["xabar"], hisob = yashir(yozuv["xabar"])
jami += hisob
print(f" [{yozuv['modul']:4}] {yozuv['xabar']}")
print(f" yashirilganlar: {dict(sorted(jami.items()))}")
print("\n=== 3. Qoldiq tekshiruvi ===")
chiqish = "\n".join(y["xabar"] for y in yozuvlar)
qolgan = {
"email": EMAIL.findall(chiqish),
"telefon": re.findall(r"\+998\s?[0-9]{2}\s?[0-9]{3}", chiqish),
"karta": re.findall(r"\b[0-9]{4}\s?[0-9]{4}\s?[0-9]{4}", chiqish),
}
print(f" to'liq email qolmadi: {qolgan['email'] == []}")
print(f" to'liq telefon qolmadi: {qolgan['telefon'] == []}")
print(f" to'liq karta qolmadi: {qolgan['karta'] == []}")
print("\n=== 4. Statistika ===")
darajalar = Counter(y["daraja"] for y in yozuvlar)
print(f" darajalar: {dict(darajalar)}")
xatolar = [f"{y['vaqt']} {y['modul']}" for y in yozuvlar if y["daraja"] == "ERROR"]
print(f" ERROR lar: {xatolar}")
muddatlar = [int(s) for y in yozuvlar for s in re.findall(r"timeout=(\d+)s", y["xabar"])]
print(f" timeout qiymatlari: {muddatlar}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Tahlil ===
tuzilgan yozuvlar: 5, buzilgan qatorlar: [5]
birinchi yozuv kalitlari: ['sana', 'vaqt', 'daraja', 'modul', 'xabar']
daraja='INFO', modul='auth'
=== 2. Yashirish ===
[auth] kirish: a***@wisar.uz, tel +998 90 *** ** 67
[pay ] karta **** **** **** 9012 rad etildi
[pay ] to'lov xatosi: user=b***@mail.uz summa=125000
[auth] parol tiklash: +998 91 *** ** 67
[db ] ulanish uzildi (timeout=30s)
yashirilganlar: {'email': 2, 'karta': 1, 'telefon': 2}
=== 3. Qoldiq tekshiruvi ===
to'liq email qolmadi: True
to'liq telefon qolmadi: True
to'liq karta qolmadi: True
=== 4. Statistika ===
darajalar: {'INFO': 2, 'WARN': 1, 'ERROR': 2}
ERROR lar: ['09:13:44 pay', '09:15:30 db']
timeout qiymatlari: [30]Nima ko'rsatdi: 2.2, 2.4, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"findall doim butun moslikni qaytaradi" |
Guruh bo'lsa — guruh(lar)ni |
"(ab)+ hamma takrorlarni ushlaydi" |
Faqat oxirgisini |
| "Mos kelmagan guruh — bo'sh satr" | Match da None, findall da '' |
"r"\10" — 1-guruh va 0" |
10-guruh; kerakligi — \g<1>0 |
"re.sub(p, r, s, re.I) — katta-kichik harfsiz" |
count=2, bayroqsiz |
"Almashtirmadagi \n — ikki belgi" |
Yangi qatorga aylanadi |
"re.split ajratgichni doim tashlaydi" |
Guruhli naqshda saqlaydi |
"re.split(r'\s+', s) = s.split()" |
Chetlarida bo'sh satr qoladi |
6. Keng tarqalgan xatolar va yechimlari
1. Pozitsion flags
re.sub(p, r, s, re.I) # ❌ count=2
re.sub(p, r, s, flags=re.I) # ✅2. Guruh qo'shilganda findall natijasi o'zgarib qolishi
re.findall(r"\d+(kg|g)", s) # ❌ faqat 'kg'/'g' qaytadi
re.findall(r"\d+(?:kg|g)", s) # ✅3. Raqamli guruhlar ko'payib ketganda
m.group(7) # ❌ naqsh o'zgarsa siljiydi
m["holat"] # ✅ nomli guruh4. None ni tekshirmaslik
m["prefiks"].upper() # ❌ AttributeError
(m["prefiks"] or "").upper() # ✅5. Tashqi matn almashtirmada
re.sub(p, foydalanuvchi_matni, s) # ❌ '\' va '\g' ma'no oladi
re.sub(p, lambda m: foydalanuvchi_matni, s) # ✅6. \10 noaniqligi
re.sub(r"(\d)", r"\10", s) # ❌
re.sub(r"(\d)", r"\g<1>0", s) # ✅7. split dan keyin bo'sh qismlar
re.split(r"\s+", " a b ") # ['', 'a', 'b', '']
[q for q in re.split(r"\s+", s) if q] # ✅8. sub ni tsiklda qayta-qayta kompilyatsiya
for s in katta_royxat:
re.sub(r"murakkab...", ...) # ⚠️ kesh bor, lekin nomli naqsh yaxshiroq
NAQSH = re.compile(r"murakkab...") # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 15.1-dars (o'tilgan): naqsh tili
- 15.3-dars: lookahead, tokenizator, ishlash tezligi
- 15.16-dars:
logging— jurnal formatlari - 16.3-dars: CSV va matn fayllarini tozalash
- 28.11-dars: markazlashgan loglar — shaxsiy ma'lumotni yashirish
- 20.4-dars: route va parametrlar
- 24-qism:
pandas.Series.str.extract— nomli guruhlar ustunga aylanadi
8. Eng yaxshi amaliyotlar
Ikkitadan ko'p guruh — nomli guruhlar.
Faqat birlashtirish uchun —
(?:...).count,maxsplit,flags— doim nomi bilan.Murakkab almashtirish — funksiya bilan.
Tashqi matnni almashtirmaga funksiya orqali qo'ying.
subnbilan nechta almashtirish bo'lganini tekshiring.Yashirishdan keyin qoldiq tekshiruvi qiling.
Naqshga nom bering va
VERBOSEbilan hujjatlashtiring.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
import re
1. print(re.search(r"(\w+)@(\w+)", "a@b").groups())
2. print(re.findall(r"(\d)(\w)", "1a 2b"))
3. print(re.findall(r"\d(\w)", "1a 2b"))
4. print(re.search(r"(a)?b", "b").group(1))
5. print(re.sub(r"(\w+) (\w+)", r"\2 \1", "salom dunyo"))
6. print(re.sub(r"\d", lambda m: str(int(m[0]) + 1), "a1b9"))
7. print(re.subn(r"o", "0", "olmos"))
8. print(re.split(r"(-)", "a-b"))
9. print(re.split(r"-", "-a-"))
10. print(re.findall(r"(ab)+", "ababab"))
11. print(re.search(r"(?P<x>\d+)", "n=42").groupdict())
12. print(re.sub(r"a", "X", "aaa", count=1))Javoblar
('a', 'b')[('1', 'a'), ('2', 'b')]['a', 'b']Nonedunyo saloma2b10('0lm0s', 2)['a', '-', 'b']['', 'a', '']['ab']— faqat oxirgi takror{'x': '42'}Xaa
Vazifa 2: Xatolarni tuzating
1. def yashir(matn):
return re.sub(r"[0-9]{16}", "****", matn, re.MULTILINE)
2. def ogirliklar(matn):
return re.findall(r"[0-9]+(kg|g)", matn) # ['12kg', '500g'] kutilgan
3. def formatla(matn):
return re.sub(r"([0-9])", r"\10", matn) # '1' → '10'
4. def yolni_qoy(shablon, yol):
return re.sub(r"\{YOL\}", yol, shablon) # yol = r"C:\new"
5. def prefiks(tel):
m = re.fullmatch(r"(\+998)?([0-9]{9})", tel)
return m.group(1).strip("+")Javoblar
1. def yashir(matn):
return re.sub(r"[0-9]{16}", "****", matn, flags=re.MULTILINE)
2. def ogirliklar(matn):
return re.findall(r"[0-9]+(?:kg|g)", matn)
3. def formatla(matn):
return re.sub(r"([0-9])", r"\g<1>0", matn)
4. def yolni_qoy(shablon, yol):
return re.sub(r"\{YOL\}", lambda m: yol, shablon)
5. def prefiks(tel):
m = re.fullmatch(r"(\+998)?([0-9]{9})", tel)
if m is None:
return None
return (m.group(1) or "+998").strip("+")Vazifa 3: Sana me'yorlagich
sanani_iso(matn) funksiyasini yozing — matndagi barcha sanalarni YYYY-MM-DD ga aylantirsin:
17.09.2026,17/09/2026,2026-09-17,17 sentabr 2026shakllari- Oy nomlari o'zbekcha (lotin) — lug'at bilan
- Nomli guruhlar va bitta
re.sub+ funksiya - Noto'g'ri sana (
31.02.2026) — o'zgarmasin va alohida ro'yxatga tushsin - 15 ta sinov bilan tekshiring
Vazifa 4: Shablon dvigateli
toldir(shablon, qiymatlar) yozing:
{{ ism }}— qiymat bilan almashtirilsin (bo'shliqlar ixtiyoriy){{ narx | pul }}— filtr:125000→125 000 so'm- Topilmagan kalit —
KeyErroremas,{{ ?ism }}qoldirilsin va ogohlantirish ro'yxatiga tushsin - Qiymat ichidagi
\va{{xavfsiz qo'yilsin subnbilan nechta joy to'ldirilganini qaytarsin
Vazifa 5: Markdown → HTML (kichik)
**qalin**→<b>qalin</b>,*kursiv*→<i>kursiv</i>`kod`ichidagi*o'zgarmasin[matn](url)→<a href="url">matn</a># Sarlavha→<h1>(MULTILINE)- Qaysi holatlarda regex yetmasligini hujjatlashtiring (15.1, Vazifa 7)
Vazifa 6: CSV qatorini ajratish
re.splitbilan,bo'yicha bo'ling, lekin qo'shtirnoq ichidagi vergul bo'linmasin"a,b",c,"d ""e"""→['a,b', 'c', 'd "e"']- Natijani
csvmoduli bilan solishtiring (16.3-dars) - Regex qaysi holatda buziladi — misol toping
Vazifa 7: O'ylash
re.sub da almashtirma satr yoki funksiya bo'lishi mumkin. Boshqa tillarda ham shunday: JavaScript'da str.replace(regex, "$1") yoki str.replace(regex, fn), Java'da Matcher.replaceAll(Function). Nega almashtirma satrining o'z "mini-tili" (\1, \g<nom>, $1) bor va bu qanday xavfsizlik muammolariga olib kelishi mumkin?
Javob
Qisqa javob: Almashtirma satr — eng ko'p uchraydigan holat (guruhlarni qayta tartiblash) uchun qisqa yozuv. Lekin u o'z mini-tiliga ega bo'lgani uchun tashqi matnni almashtirma sifatida qo'yish — bu "kod va ma'lumotni aralashtirish" xatosi: SQL injection bilan bir oiladan. Yechim ham bir xil — ma'lumotni kod sifatida talqin qilinmaydigan kanal orqali uzatish (funksiya).
1. Mini-til nima uchun kerak
| Vazifa | Satr bilan | Funksiya bilan |
|---|---|---|
| Sanani qayta tartiblash | r"\3.\2.\1" |
lambda m: f"{m[3]}.{m[2]}.{m[1]}" |
| Butun moslikni o'rash | r"[\g<0>]" |
lambda m: f"[{m[0]}]" |
Satr qisqa, o'qiladi va C darajasida bir marta tahlil qilinadi — tez.
2. Tillar bo'yicha
| Til | Guruh havolasi | Butun moslik | Funksiya |
|---|---|---|---|
| Python | \1, \g<nom> |
\g<0> |
|
| JavaScript | $1, $<nom> |
$& |
|
| Java | $1, ${nom} |
$0 |
(replaceAll(Function)) |
| .NET | $1, ${nom} |
$0 |
(MatchEvaluator) |
3. Xavfsizlik muammolari
| Muammo | Misol |
|---|---|
| Kutilmagan talqin | Windows yo'li C:\new → \n yangi qatorga aylanadi |
| Istisno (DoS) | Foydalanuvchi \9 yozsa — PatternError, so'rov yiqiladi |
| Ma'lumot sizishi | JavaScript'da $\`` va $'— moslikdan oldingi/keyingi **butun matnni** qo'yadi; foydalanuvchi nomi$'` bo'lsa, boshqa ma'lumot javobga tushadi |
| Shablon injection | Almashtirma keyinroq boshqa shablon dvigatelidan o'tsa |
4. Umumiy tamoyil
Bu — kod va ma'lumotni ajratish tamoyili:
| Soha | Xato | To'g'ri |
|---|---|---|
| SQL | f"... WHERE ism='{ism}'" |
Parametrlangan so'rov |
| Shell | os.system(f"ls {yol}") |
subprocess.run(["ls", yol]) |
| HTML | Satr birlashtirish | Avtomatik ekranlovchi shablon |
| Regex naqsh | re.search(soz, ...) |
re.escape(soz) |
| Regex almashtirma | re.sub(p, matn, ...) |
lambda m: matn |
5. Xulosa
- Almashtirma mini-tili — qulaylik uchun
- Tashqi matn bu tilda talqin qilinsa — xato, istisno yoki ma'lumot sizishi
- Yechim: ma'lumotni funksiya orqali uzatish — u talqin qilinmaydi
- Bu SQL, shell va HTML dagi injection lar bilan bir xil sinf xato
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda naqshdan ma'lumot ajratish va matnni o'zgartirishni o'rgandik.
Eng muhim uch fikr:
Guruhlar — naqsh ichidan ma'lumot olish.
(...)ushlaydi,(?:...)faqat birlashtiradi,(?P<nom>...)esa nom beradi vagroupdict()bilan to'g'ridan-to'g'ri lug'at qaytaradi.findallnatijasi guruhlar soniga bog'liq — bitta guruh qo'shish butun natijani o'zgartiradi. Mos kelmagan guruhMatchdaNone,findallda''; takrorlangan guruh faqat oxirgi takrorni saqlaydi.re.sub— almashtirma satr yoki funksiya. Satrda\1,\g<nom>,\g<0>ishlaydi, guruhdan keyin raqam kelsa —\g<1>0. Funksiya harMatchuchun chaqiriladi va uning natijasi talqin qilinmaydi — shuning uchun tashqi matnni almashtirmaga faqat funksiya orqali qo'yish kerak.subnalmashtirishlar sonini ham qaytaradi.count,maxsplit,flags— doim nomi bilan.re.sub(p, r, s, re.I)dare.Ibayroq emas,count=2bo'lib qoladi — jim, xatosiz, faqat 3.13+ da ogohlantirish bilan.re.splitesa guruhli naqshda ajratgichlarni natijada saqlaydi va chetlarda bo'sh satrlar qoldiradi.
Keyingi darsda amaliy naqshlarga o'tamiz: lookahead va lookbehind, tokenizator yozish, katastrofik backtracking va regexni qachon ishlatmaslik kerak.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!