Mundarija (23)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Satr — Unicode kod nuqtalari ketma-ketligi
- 2.2. ord() va chr()
- 2.3. CPython satrni qanday saqlaydi
- 2.4. Indekslash — batafsil
- 2.5. Iteratsiya usullari
- 2.6. Internlash — nega ba'zi satrlar bitta obyekt
- 2.7. Satr va ro'yxat — farqi
- 2.8. Grafema — ko'rinadigan belgi
- 2.9. Foydali funksiyalar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Satrning ichki tuzilishini o'rganish
- Misol 2 — ord/chr bilan amaliy masalalar
- Misol 3 — Internlash tajribasi
- Misol 4 — Grafema muammosi
- 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
4.1-dars: Satrning ichki tuzilishi va indekslash
4-QISM — SATRLAR CHUQUR · 1-dars
1. Kirish va motivatsiya
3.7-darsda satrlar bilan tanishdik: yaratish, indekslash, asosiy metodlar. Endi ichkariga kiramiz.
Nega bu kerak? Chunki satrlar bilan bog'liq eng chalkash savollar aynan ichki tuzilishdan kelib chiqadi:
matn = "salom"
print(len(matn)) # 5
matn = "салом"
print(len(matn)) # 5
print(len(matn.encode("utf-8"))) # 10 — nega ikki barobar?import sys
print(sys.getsizeof("a")) # 50
print(sys.getsizeof("ы")) # 76 — nega ko'proq?
print(sys.getsizeof("😊")) # 80a = "salom"
b = "salom"
print(a is b) # True
a = "salom dunyo!"
b = "salom dunyo!"
print(a is b) # False — nega endi yo'q?Bu darsda:
- CPython satrni qanday saqlaydi (kompakt Unicode ko'rinishi)
- Kod nuqtasi, belgi va grafema farqi
ord(),chr()va Unicode jadvali- Internlash — nega ba'zi satrlar bitta obyekt
- Indekslash tezligi va nima uchun
strlistga o'xshamaydi
2. Nazariya — chuqur tushuntirish
2.1. Satr — Unicode kod nuqtalari ketma-ketligi
3.7-darsda aytgandik: Python 3 da satr — belgilar ketma-ketligi, baytlar emas.
Aniqrog'i: satr — Unicode kod nuqtalari (code points) ketma-ketligi.
matn = "salom"
for belgi in matn:
print(f" {belgi!r} → U+{ord(belgi):04X} ({ord(belgi)})") 's' → U+0073 (115)
'a' → U+0061 (97)
'l' → U+006C (108)
'o' → U+006F (111)
'm' → U+006D (109)U+0073 — Unicode standartidagi rasmiy yozuv. 0x73 = 115.
Unicode nima? Dunyodagi barcha yozuv tizimining barcha belgisiga noyob raqam beruvchi standart. 2026-yil holatiga ko'ra 149 000 dan ortiq belgi.
U+0000 – U+007F ASCII (lotin, raqam, tinish)
U+0080 – U+07FF Kirillitsa, arab, ibroniy, yunon
U+0800 – U+FFFF Xitoy, yapon, koreys va boshqalar
U+10000 – U+10FFFF Emoji, qadimiy yozuvlar, matematik belgilar8-darsda Unicode ni to'liq o'rganamiz. Hozircha: har bir belgi — bitta raqam.
2.2. ord() va chr()
print(ord("A")) # 65
print(ord("a")) # 97
print(ord("0")) # 48
print(ord("я")) # 1103
print(ord("中")) # 20013
print(ord("😊")) # 128522
print(chr(65)) # 'A'
print(chr(1103)) # 'я'
print(chr(128522)) # '😊'Foydali qonuniyatlar:
# Lotin harflari ketma-ket
print(ord("a"), ord("b"), ord("z")) # 97 98 122
print(ord("A"), ord("Z")) # 65 90
# Katta va kichik harf farqi — doim 32
print(ord("a") - ord("A")) # 32
# Raqamlar ham ketma-ket
print(ord("0"), ord("9")) # 48 57
print(ord("7") - ord("0")) # 7 ← raqamni songa aylantirishAmaliy foydalanish:
# Sezar shifri (eng oddiy shifrlash)
def sezar(matn: str, siljish: int) -> str:
natija = []
for h in matn:
if "a" <= h <= "z":
natija.append(chr((ord(h) - ord("a") + siljish) % 26 + ord("a")))
elif "A" <= h <= "Z":
natija.append(chr((ord(h) - ord("A") + siljish) % 26 + ord("A")))
else:
natija.append(h)
return "".join(natija)
print(sezar("salom dunyo", 3)) # 'vdorp gxqbr'
print(sezar("vdorp gxqbr", -3)) # 'salom dunyo'% 26 — 3.3-darsdagi aylanma indeks naqshi.
Alifboni hosil qilish:
alifbo = "".join(chr(ord("a") + i) for i in range(26))
print(alifbo) # abcdefghijklmnopqrstuvwxyz
# Yoki tayyor:
import string
print(string.ascii_lowercase) # abcdefghijklmnopqrstuvwxyz
print(string.ascii_uppercase)
print(string.digits) # 0123456789
print(string.punctuation)2.3. CPython satrni qanday saqlaydi
Bu — PEP 393 "Flexible String Representation" (Python 3.3+).
Muammo: har bir belgini 4 baytda saqlash xotira isrofi. "salom" uchun 20 bayt kerak bo'lardi, aslida 5 yetadi.
Yechim: CPython satrdagi eng katta kod nuqtasiga qarab saqlash usulini tanlaydi:
| Eng katta kod nuqtasi | Har belgi uchun | Nomi |
|---|---|---|
| ≤ U+00FF (255) | 1 bayt | Latin-1 |
| ≤ U+FFFF (65535) | 2 bayt | UCS-2 |
| ≤ U+10FFFF | 4 bayt | UCS-4 |
import sys
namunalar = [
"", # bo'sh
"a", # ASCII
"abc",
"abcdefghij",
"é", # Latin-1 chegarasida
"ы", # kirillitsa → 2 bayt
"abcы", # BITTA kirillitsa hammasini 2 baytga o'tkazadi
"中", # xitoy → 2 bayt
"😊", # emoji → 4 bayt
"abc😊", # BITTA emoji hammasini 4 baytga
]
print(f"{'Satr':<12} {'Uzunlik':>8} {'Xotira':>8} {'Belgi/bayt':>12}")
print("─" * 44)
for s in namunalar:
hajm = sys.getsizeof(s)
bayt = (hajm - sys.getsizeof("")) / len(s) if s else 0
print(f"{s!r:<12} {len(s):>8} {hajm:>8} {bayt:>12.1f}")Satr Uzunlik Xotira Belgi/bayt
────────────────────────────────────────────
'' 0 49 0.0
'a' 1 50 1.0
'abc' 3 52 1.0
'abcdefghij' 10 59 1.0
'é' 1 75 26.0
'ы' 1 76 27.0
'abcы' 4 82 8.2
'中' 1 76 27.0
'😊' 1 80 31.0
'abc😊' 4 92 10.8Muhim kuzatish: "abcы" — to'rt belgi, lekin bitta kirillitsa harfi butun satrni 2 baytli rejimga o'tkazdi.
Amaliy natija:
# Katta matnda bitta emoji xotirani 4 barobar oshiradi
oddiy = "a" * 1_000_000
emojili = "a" * 999_999 + "😊"
print(f"Oddiy: {sys.getsizeof(oddiy):>12,} bayt")
print(f"Emojili: {sys.getsizeof(emojili):>12,} bayt")Oddiy: 1,000,049 bayt
Emojili: 4,000,056 baytBu — katta matn qayta ishlashda ahamiyatli bo'lishi mumkin.
Nega bunday qilingan? Chunki indekslash O(1) bo'lishi kerak. Agar belgilar turli uzunlikda saqlansa (UTF-8 kabi), matn[1000] ni topish uchun boshidan sanash kerak bo'lardi — O(n).
Sobit uzunlik → to'g'ridan-to'g'ri hisoblash:
manzil = boshlanish + indeks × bayt_uzunligi2.4. Indekslash — batafsil
matn = "Python"
# P y t h o n
# 0 1 2 3 4 5
# -6 -5 -4 -3 -2 -1
print(matn[0]) # 'P'
print(matn[5]) # 'n'
print(matn[-1]) # 'n'
print(matn[-6]) # 'P'Manfiy indeks formulasi:
matn[-i] ≡ matn[len(matn) - i]print(matn[-2] == matn[len(matn) - 2]) # TrueChegaradan chiqish:
print(matn[6]) # ❌ IndexError: string index out of range
print(matn[-7]) # ❌ IndexErrorKesimlar esa xato bermaydi (2-darsda batafsil):
print(matn[6:]) # '' — bo'sh satr
print(matn[10:20]) # ''Xavfsiz indekslash:
def xavfsiz_olish(matn: str, indeks: int, sukut: str = "") -> str:
"""Indeks bo'yicha belgini xavfsiz qaytaradi."""
if -len(matn) <= indeks < len(matn):
return matn[indeks]
return sukut
print(xavfsiz_olish("abc", 1)) # 'b'
print(xavfsiz_olish("abc", 10)) # ''
print(xavfsiz_olish("abc", 10, "?")) # '?'Yoki kesim bilan (soddaroq):
print("abc"[10:11] or "?") # '?'Belgi ham satr:
belgi = matn[0]
print(type(belgi)) # <class 'str'>
print(len(belgi)) # 1
print(belgi[0]) # 'P' — o'zi
print(belgi[0][0][0]) # 'P' — cheksizPythonda alohida char turi yo'q. Bu — soddalik, lekin ba'zan chalkashtiradi.
2.5. Iteratsiya usullari
matn = "salom"
# 1. To'g'ridan-to'g'ri (eng oddiy va tez)
for harf in matn:
print(harf, end=" ")
print()
# 2. Indeks bilan
for i in range(len(matn)):
print(f"{i}:{matn[i]}", end=" ")
print()
# 3. enumerate — ikkalasi (TAVSIYA ETILADI)
for i, harf in enumerate(matn):
print(f"{i}:{harf}", end=" ")
print()
# 4. Teskari
for harf in reversed(matn):
print(harf, end=" ")
print()
# 5. Indeks va teskari
for i, harf in enumerate(reversed(matn)):
print(f"{i}:{harf}", end=" ")
print()s a l o m
0:s 1:a 2:l 3:o 4:m
0:s 1:a 2:l 3:o 4:m
m o l a s
0:m 1:o 2:l 3:a 4:senumerate boshlang'ich qiymat bilan:
for raqam, harf in enumerate(matn, start=1):
print(f"{raqam}-belgi: {harf}")5-qismda iteratsiyani to'liq o'rganamiz.
Tezlik:
import time
matn = "a" * 1_000_000
boshlandi = time.perf_counter()
for h in matn:
pass
vaqt_toGridan = time.perf_counter() - boshlandi
boshlandi = time.perf_counter()
for i in range(len(matn)):
matn[i]
vaqt_indeks = time.perf_counter() - boshlandi
print(f"To'g'ridan: {vaqt_toGridan * 1000:>7.1f} ms")
print(f"Indeks: {vaqt_indeks * 1000:>7.1f} ms")To'g'ridan-to'g'ri iteratsiya odatda 2-3 barobar tezroq — chunki range obyekti va indekslash amali qo'shimcha xarajat.
2.6. Internlash — nega ba'zi satrlar bitta obyekt
3.1-darsda tegib o'tgandik. Endi batafsil.
a = "salom"
b = "salom"
print(a is b) # True
a = "salom dunyo!"
b = "salom dunyo!"
print(a is b) # FalseInternlash (interning) — bir xil satrni xotirada bir marta saqlash optimizatsiyasi.
CPython qanday satrlarni avtomatik internlaydi:
- Kompilyatsiya paytidagi doimiylar — kodda yozilgan satrlar
- Identifikatorga o'xshash satrlar — faqat harf, raqam va
_dan iborat - Bo'sh satr va bitta belgili satrlar
# ✅ Internlanadi (identifikatorga o'xshash)
a = "salom"
b = "salom"
print(a is b) # True
a = "foydalanuvchi_ismi"
b = "foydalanuvchi_ismi"
print(a is b) # True
# ❌ Internlanmaydi (bo'sh joy va tinish belgisi bor)
a = "salom dunyo!"
b = "salom dunyo!"
print(a is b) # False — interaktiv rejimda (REPL) Nozik joy: oxirgi misolni .py faylga yozib ishga tushirsangiz, True chiqadi! Kompilyator bitta kod obyektidagi bir xil satr doimiylarini birlashtiradi — bu internlash emas, doimiylarni takrorlamaslik. REPL'da esa har qator alohida kompilyatsiya qilinadi, shuning uchun False. Xulosa bir xil: is natijasi kontekstga bog'liq, unga tayanib bo'lmaydi.
Ishlash paytida yaratilgan satrlar internlanmaydi:
a = "salom"
b = "sal" + "om" # kompilyatsiya paytida birlashadi
print(a is b) # True
qism = "sal"
c = qism + "om" # ishlash paytida
print(a is c) # False
print(a == c) # TrueQo'lda internlash:
import sys
a = "salom dunyo!"
b = sys.intern("salom dunyo!")
c = sys.intern("salom dunyo!")
print(a is b) # False (REPL'da; bitta faylda True bo'lishi mumkin)
print(b is c) # True — har doimQachon foydali? Ko'p takrorlanadigan satrlar bilan ishlaganda:
# Katta ma'lumotda ustun nomlari millionlab marta takrorlanadi
import sys
ustunlar = [sys.intern(nom) for nom in ["ism", "yosh", "shahar"]]
# Endi taqqoslash `is` bilan tez ishlaydi va xotira tejaydiAmaliy qoida:
Internlash — optimizatsiya tafsiloti, kafolat emas.
isni satrlar bilan hech qachon ishlatmang.
if matn is "salom": # ❌ ishonchsiz, SyntaxWarning
if matn == "salom": # ✅2.7. Satr va ro'yxat — farqi
Satr ro'yxatga o'xshaydi, lekin muhim farqlar bor:
matn = "salom"
royxat = list(matn) # ['s', 'a', 'l', 'o', 'm']
# ✅ Ikkalasida ishlaydi
print(matn[0], royxat[0])
print(len(matn), len(royxat))
print(matn[1:3], royxat[1:3])
print("a" in matn, "a" in royxat)
# ❌ Faqat ro'yxatda
royxat[0] = "S" # ✅
# matn[0] = "S" # ❌ TypeError
royxat.append("!") # ✅
# matn.append("!") # ❌ AttributeErrorAsosiy farqlar:
str |
list |
|
|---|---|---|
| O'zgaruvchanlik | O'zgarmas | O'zgaruvchan |
| Elementlar | Faqat belgilar | Har qanday obyekt |
in |
Pastki satr qidiradi | Elementni qidiradi |
| Xeshlanadimi | Ha (kalit bo'la oladi) | Yo'q |
| Xotira | Ixcham | Ko'proq |
in ning farqi — muhim:
print("lo" in "salom") # True — pastki satr
print("lo" in ["s","a","l","o","m"]) # False — bunday element yo'q
print("l" in ["s","a","l","o","m"]) # TrueXeshlanish:
lugat = {"salom": 1} # ✅ satr kalit bo'la oladi
# lugat = {["a"]: 1} # ❌ TypeError: unhashable type
print(hash("salom")) # har seansda boshqa (xavfsizlik uchun)Xesh har dastur ishga tushganda o'zgaradi — bu xesh to'qnashuvi hujumlaridan himoya (PYTHONHASHSEED).
Satrni "o'zgartirish" uchun ro'yxatga o'tish:
matn = "salom"
# ❌ Ishlamaydi
# matn[0] = "S"
# ✅ Ro'yxat orqali
harflar = list(matn)
harflar[0] = "S"
matn = "".join(harflar)
print(matn) # 'Salom'
# ✅ Yoki kesim bilan (soddaroq)
matn = "salom"
matn = "S" + matn[1:]
print(matn) # 'Salom'2.8. Grafema — ko'rinadigan belgi
Bu — nozik, lekin muhim mavzu.
Bir "belgi" bir kod nuqtasi bo'lmasligi mumkin:
# Bir xil ko'rinadi, turli tuzilma
a = "é" # U+00E9 — tayyor belgi
b = "é" # U+0065 + U+0301 (e + urg'u)
print(a, b) # é é — bir xil ko'rinadi
print(a == b) # False!
print(len(a), len(b)) # 1 2
print([hex(ord(c)) for c in a]) # ['0xe9']
print([hex(ord(c)) for c in b]) # ['0x65', '0x301']Normalizatsiya bu muammoni hal qiladi:
import unicodedata
a = "é"
b = "é"
print(unicodedata.normalize("NFC", a) == unicodedata.normalize("NFC", b)) # True
print(len(unicodedata.normalize("NFC", b))) # 1
print(len(unicodedata.normalize("NFD", a))) # 2| Shakl | Nima qiladi |
|---|---|
NFC |
Birlashtiradi (tayyor belgi) |
NFD |
Ajratadi (asos + belgi) |
NFKC |
Birlashtiradi + moslik almashtirish |
NFKD |
Ajratadi + moslik almashtirish |
Emoji bilan yanada murakkab:
oila = "👨👩👧👦"
print(len(oila)) # 7! — bitta emoji ko'rinadi
print([hex(ord(c)) for c in oila])7
['0x1f468', '0x200d', '0x1f469', '0x200d', '0x1f467', '0x200d', '0x1f466']0x200d — "Zero Width Joiner", belgilarni birlashtiradi.
Amaliy natija:
matn = "Salom 👨👩👧👦"
print(len(matn)) # 13, lekin ko'zga 7 ta ko'rinadi
print(matn[:7]) # 'Salom 👨' — emoji buzildi!Yechim: grafemalar bilan ishlash uchun tashqi kutubxona kerak:
pip install graphemeimport grapheme
print(grapheme.length("👨👩👧👦")) # 1Amaliy maslahat: oddiy matn bilan ishlaganda bu haqda o'ylash shart emas. Lekin foydalanuvchi kiritmasi, ism, izoh bilan ishlaganda (ayniqsa uzunlikni cheklashda) e'tiborga oling.
2.9. Foydali funksiyalar
import string
import unicodedata
matn = "Salom, Dunyo! 123"
# Tekshirish (3.7-darsdan)
print("abc".isalpha()) # True
print("123".isdigit()) # True
print("abc123".isalnum()) # True
print(" ".isspace()) # True
print("Salom".istitle()) # True
# Unicode ma'lumoti
for belgi in "Aя中😊":
print(f" {belgi} U+{ord(belgi):05X} "
f"{unicodedata.category(belgi):<3} "
f"{unicodedata.name(belgi, '?')}") A U+00041 Lu LATIN CAPITAL LETTER A
я U+0044F Ll CYRILLIC SMALL LETTER YA
中 U+04E2D Lo CJK UNIFIED IDEOGRAPH-4E2D
😊 U+1F60A So SMILING FACE WITH SMILING EYESKategoriyalar:
| Kod | Ma'nosi |
|---|---|
Lu |
Katta harf |
Ll |
Kichik harf |
Lo |
Boshqa harf (xitoy, arab) |
Nd |
O'nlik raqam |
Zs |
Bo'sh joy |
So |
Boshqa belgi (emoji) |
Po |
Tinish belgisi |
string moduli doimiylari:
print(string.ascii_letters) # a-zA-Z
print(string.ascii_lowercase) # a-z
print(string.digits) # 0-9
print(string.punctuation) # !"#$%&'()*+,-./...
print(string.whitespace) # ' \t\n\r\x0b\x0c'
print(string.printable) # hammasi3. Tez ma'lumotnoma
Kod nuqtalari
ord("A") → 65
chr(65) → 'A'
f"U+{ord(c):04X}" → 'U+0041'Ichki saqlash (PEP 393)
≤ U+00FF → 1 bayt/belgi
≤ U+FFFF → 2 bayt/belgi
> U+FFFF → 4 bayt/belgi
Bitta emoji butun satrni 4 baytli rejimga o'tkazadiIndekslash
matn[0] birinchi
matn[-1] oxirgi
matn[-i] ≡ matn[len(matn) - i]
matn[10] IndexError
matn[10:11] '' — xavfsizIteratsiya
for h in matn: eng tez
for i, h in enumerate(matn): indeks kerak bo'lsa
for h in reversed(matn): teskariInternlash
Identifikatorga o'xshash satrlar avtomatik internlanadi
sys.intern(s) — qo'lda
⚠️ `is` ni satrlar bilan ISHLATMANGUnicode
unicodedata.name(c) belgi nomi
unicodedata.category(c) kategoriya
unicodedata.normalize("NFC", s) normalizatsiya4. Batafsil misollar
Misol 1 — Satrning ichki tuzilishini o'rganish
"""CPython satrni qanday saqlaydi."""
import sys
import unicodedata
def tahlil(matn: str) -> None:
"""Satrning ichki tuzilishini ko'rsatadi."""
hajm = sys.getsizeof(matn)
bosh_hajm = sys.getsizeof("")
belgi_hajmi = (hajm - bosh_hajm) / len(matn) if matn else 0
# Saqlash rejimini aniqlash
eng_katta = max((ord(c) for c in matn), default=0)
if eng_katta <= 0xFF:
rejim = "Latin-1 (1 bayt)"
elif eng_katta <= 0xFFFF:
rejim = "UCS-2 (2 bayt)"
else:
rejim = "UCS-4 (4 bayt)"
print(f" Satr: {matn!r}")
print(f" Uzunlik: {len(matn)} belgi")
print(f" Xotira: {hajm} bayt")
print(f" Belgi hajmi: ~{belgi_hajmi:.1f} bayt")
print(f" Saqlash rejimi: {rejim}")
print(f" Eng katta kod: U+{eng_katta:04X}")
print(f" UTF-8 da: {len(matn.encode('utf-8'))} bayt")
print()
print("=== Turli satrlar ===\n")
for m in ["abcdefghij", "abcdefghiы", "abcdefghi😊", "салом", "中文"]:
tahlil(m)
print("=== Bitta belgi hammasini o'zgartiradi ===")
asos = "a" * 100
print(f" 100 ta 'a': {sys.getsizeof(asos):>8,} bayt")
print(f" 99 ta 'a' + 'ы': {sys.getsizeof('a' * 99 + 'ы'):>8,} bayt")
print(f" 99 ta 'a' + '😊': {sys.getsizeof('a' * 99 + '😊'):>8,} bayt")
print("\n=== Katta matnda farq ===")
N = 1_000_000
oddiy = "a" * N
emojili = "a" * (N - 1) + "😊"
print(f" {N:,} ta ASCII: {sys.getsizeof(oddiy):>12,} bayt")
print(f" {N:,} + 1 emoji: {sys.getsizeof(emojili):>12,} bayt")
print(f" Farq: {sys.getsizeof(emojili) / sys.getsizeof(oddiy):>12.1f}x")=== Turli satrlar ===
Satr: 'abcdefghij'
Uzunlik: 10 belgi
Xotira: 59 bayt
Belgi hajmi: ~1.0 bayt
Saqlash rejimi: Latin-1 (1 bayt)
Eng katta kod: U+006A
UTF-8 da: 10 bayt
Satr: 'abcdefghiы'
Uzunlik: 10 belgi
Xotira: 94 bayt
Belgi hajmi: ~4.5 bayt
Saqlash rejimi: UCS-2 (2 bayt)
Eng katta kod: U+044B
UTF-8 da: 11 bayt
Satr: 'abcdefghi😊'
Uzunlik: 10 belgi
Xotira: 96 bayt
Belgi hajmi: ~4.7 bayt
Saqlash rejimi: UCS-4 (4 bayt)
Eng katta kod: U+1F60A
UTF-8 da: 13 bayt
=== Bitta belgi hammasini o'zgartiradi ===
100 ta 'a': 149 bayt
99 ta 'a' + 'ы': 274 bayt
99 ta 'a' + '😊': 476 bayt
=== Katta matnda farq ===
1,000,000 ta ASCII: 1,000,049 bayt
1,000,000 + 1 emoji: 4,000,056 bayt
Farq: 4.0xNima ko'rsatdi: 2.3-bo'lim. Bitta belgi butun satrning xotira sarfini 4 barobar oshirishi mumkin.
Misol 2 — ord/chr bilan amaliy masalalar
"""Kod nuqtalari bilan ishlash."""
import string
def sezar(matn: str, siljish: int) -> str:
"""Sezar shifri — harflarni siljitadi."""
natija = []
for h in matn:
if "a" <= h <= "z":
yangi = (ord(h) - ord("a") + siljish) % 26 + ord("a")
natija.append(chr(yangi))
elif "A" <= h <= "Z":
yangi = (ord(h) - ord("A") + siljish) % 26 + ord("A")
natija.append(chr(yangi))
else:
natija.append(h)
return "".join(natija)
def harf_pozitsiyasi(harf: str) -> int:
"""Harfning alifbodagi o'rnini qaytaradi (a=1)."""
return ord(harf.lower()) - ord("a") + 1
def raqamga(belgi: str) -> int:
"""Raqam belgisini songa aylantiradi."""
return ord(belgi) - ord("0")
def registr_almashtir(matn: str) -> str:
"""Katta-kichik harfni almashtiradi (32 farqidan foydalanib)."""
natija = []
for h in matn:
if "a" <= h <= "z":
natija.append(chr(ord(h) - 32))
elif "A" <= h <= "Z":
natija.append(chr(ord(h) + 32))
else:
natija.append(h)
return "".join(natija)
print("=== Sezar shifri ===")
asl = "Salom, dunyo!"
shifr = sezar(asl, 3)
print(f" Asl: {asl}")
print(f" Shifr: {shifr}")
print(f" Ochilgan: {sezar(shifr, -3)}")
print("\n=== Alifbodagi o'rin ===")
for h in "abzABZ":
print(f" {h!r} → {harf_pozitsiyasi(h):>2}")
print("\n=== Raqam belgisini songa ===")
raqamlar = "12345"
print(f" {raqamlar!r} → {[raqamga(r) for r in raqamlar]}")
print(f" Yig'indi: {sum(raqamga(r) for r in raqamlar)}")
print("\n=== Registr almashtirish ===")
print(f" {registr_almashtir('Salom Dunyo 123')}")
print("\n=== Alifbo hosil qilish ===")
print(f" chr bilan: {''.join(chr(ord('a') + i) for i in range(26))}")
print(f" string: {string.ascii_lowercase}")
print("\n=== Belgi kodlari jadvali ===")
print(f" {'Belgi':<8} {'Dec':>6} {'Hex':>8} {'Unicode':>10}")
print(" " + "─" * 34)
for h in "aA0 !ы中😊":
print(f" {h!r:<8} {ord(h):>6} {ord(h):>8X} {'U+' + format(ord(h), '04X'):>10}")=== Sezar shifri ===
Asl: Salom, dunyo!
Shifr: Vdorp, gxqbr!
Ochilgan: Salom, dunyo!
=== Alifbodagi o'rin ===
'a' → 1
'b' → 2
'z' → 26
'A' → 1
'B' → 2
'Z' → 26
=== Raqam belgisini songa ===
'12345' → [1, 2, 3, 4, 5]
Yig'indi: 15
=== Registr almashtirish ===
sALOM dUNYO 123
=== Alifbo hosil qilish ===
chr bilan: abcdefghijklmnopqrstuvwxyz
string: abcdefghijklmnopqrstuvwxyz
=== Belgi kodlari jadvali ===
Belgi Dec Hex Unicode
──────────────────────────────────
'a' 97 61 U+0061
'A' 65 41 U+0041
'0' 48 30 U+0030
' ' 32 20 U+0020
'!' 33 21 U+0021
'ы' 1099 44B U+044B
'中' 20013 4E2D U+4E2D
'😊' 128522 1F60A U+1F60ANima ko'rsatdi: 2.2-bo'lim.
Misol 3 — Internlash tajribasi
"""Satr internlashini kuzatish."""
import sys
def tekshir(nom: str, a: str, b: str) -> None:
belgi = "✅ bitta obyekt" if a is b else "❌ ikkita obyekt"
print(f" {nom:<38} {belgi}")
print("=== 1. Kodda yozilgan satrlar ===")
a = "salom"
b = "salom"
tekshir("'salom' — identifikatorga o'xshash", a, b)
a = "foydalanuvchi_ismi"
b = "foydalanuvchi_ismi"
tekshir("'foydalanuvchi_ismi'", a, b)
a = "salom dunyo!"
b = "salom dunyo!"
tekshir("'salom dunyo!' (bitta faylda)", a, b)
def alohida(kod: str) -> str:
"""Satrni ALOHIDA kompilyatsiya qiladi — REPL'dagi kabi."""
return eval(compile(kod, "<alohida>", "eval"))
tekshir("'salom dunyo!' (alohida kompilyatsiya)",
alohida('"salom dunyo!"'), alohida('"salom dunyo!"'))
tekshir("'salom' (alohida kompilyatsiya)",
alohida('"salom"'), alohida('"salom"'))
a = ""
b = ""
tekshir("bo'sh satr", a, b)
a = "x"
b = "x"
tekshir("bitta belgi", a, b)
print("\n=== 2. Kompilyatsiya vs ishlash paytida ===")
a = "salom"
b = "sal" + "om" # kompilyator birlashtiradi
tekshir("'sal' + 'om' (doimiylar)", a, b)
qism = "sal"
c = qism + "om" # ishlash paytida
tekshir("qism + 'om' (o'zgaruvchi)", a, c)
print(f" {'Lekin == bilan:':<38} {a == c}")
print("\n=== 3. sys.intern bilan ===")
a = alohida('"salom dunyo!"')
b = alohida('"salom dunyo!"')
c = sys.intern(alohida('"salom dunyo!"'))
d = sys.intern(alohida('"salom dunyo!"'))
tekshir("internlanmagan a va b", a, b)
tekshir("internlangan c va d", c, d)
print("\n=== 4. Xotira tejash namoyishi ===")
N = 100_000
# Har biri alohida obyekt
alohida = [f"ustun_{i % 10}" for i in range(N)]
# Internlangan
internlangan = [sys.intern(f"ustun_{i % 10}") for i in range(N)]
noyob_alohida = len({id(s) for s in alohida})
noyob_intern = len({id(s) for s in internlangan})
print(f" {N:,} ta satr, 10 xil qiymat")
print(f" Internlashsiz noyob obyektlar: {noyob_alohida:>8,}")
print(f" Internlash bilan: {noyob_intern:>8,}")
print("\n=== 5. ⚠️ NEGA `is` ISHLATMASLIK KERAK ===")
kutilgan = "ha"
harf = "h"
kirish = harf + "a" # ishlash paytida — foydalanuvchi kiritgandek
print(f" kirish = harf + 'a' = {kirish!r}")
print(f" kirish is kutilgan → {kirish is kutilgan}")
print(f" kirish == kutilgan → {kirish == kutilgan}")
print("\n Xulosa: satrlar bilan DOIM == ishlating.")Natijaning muhim qismi:
=== 1. Kodda yozilgan satrlar ===
'salom' — identifikatorga o'xshash ✅ bitta obyekt
'foydalanuvchi_ismi' ✅ bitta obyekt
'salom dunyo!' (bitta faylda) ✅ bitta obyekt
'salom dunyo!' (alohida kompilyatsiya) ❌ ikkita obyekt
'salom' (alohida kompilyatsiya) ✅ bitta obyekt
bo'sh satr ✅ bitta obyekt
bitta belgi ✅ bitta obyekt
=== 2. Kompilyatsiya vs ishlash paytida ===
'sal' + 'om' (doimiylar) ✅ bitta obyekt
qism + 'om' (o'zgaruvchi) ❌ ikkita obyekt
Lekin == bilan: True
=== 3. sys.intern bilan ===
internlanmagan a va b ❌ ikkita obyekt
internlangan c va d ✅ bitta obyekt
=== 4. Xotira tejash namoyishi ===
100,000 ta satr, 10 xil qiymat
Internlashsiz noyob obyektlar: 100,000
Internlash bilan: 10Eslatma:
isnatijalari CPython'ning amalga oshiruv tafsiloti — versiya va kontekstga (fayl yoki REPL) qarab o'zgaradi. Satrlarni doim==bilan solishtiring.
Nima ko'rsatdi: 2.6-bo'lim.
Misol 4 — Grafema muammosi
"""Ko'rinadigan belgi va kod nuqtasi farqi."""
import unicodedata
def tahlil(matn: str, nom: str) -> None:
print(f"\n {nom}: {matn!r}")
print(f" Ko'rinishi: {matn}")
print(f" len(): {len(matn)}")
print(f" Kod nuqtalari:")
for c in matn:
ism = unicodedata.name(c, "NOMA'LUM")
print(f" U+{ord(c):05X} {unicodedata.category(c)} {ism}")
print("=== 1. Bir xil ko'rinish, turli tuzilma ===")
tayyor = "é" # U+00E9
qismli = "é" # e + urg'u
tahlil(tayyor, "Tayyor belgi (NFC)")
tahlil(qismli, "Qismlardan (NFD)")
print(f"\n Teng? {tayyor == qismli}")
print(f" NFC dan keyin: "
f"{unicodedata.normalize('NFC', tayyor) == unicodedata.normalize('NFC', qismli)}")
print("\n\n=== 2. Emoji — bir belgi, ko'p kod nuqtasi ===")
oila = "👨👩👧👦"
tahlil(oila, "Oila emojisi")
print("\n Kesish muammosi:")
matn = "Salom 👨👩👧👦 dunyo"
print(f" To'liq: {matn}")
print(f" len(): {len(matn)}")
print(f" matn[:8]: {matn[:8]} ← emoji buzildi")
print(f" matn[:13]: {matn[:13]}")
print("\n\n=== 3. Amaliy: qidiruv muammosi ===")
foydalanuvchilar = ["José", "José", "Jose"]
qidiruv = "José"
print(f" Qidiruv: {qidiruv!r}")
for f in foydalanuvchilar:
oddiy = f == qidiruv
normal = (unicodedata.normalize("NFC", f)
== unicodedata.normalize("NFC", qidiruv))
print(f" {f!r:<16} oddiy={oddiy!s:<6} normalizatsiya bilan={normal}")
print("\n\n=== 4. Yechim: doim normalizatsiya qiling ===")
def normalize(matn: str) -> str:
"""Qidiruv va solishtirish uchun matnni normallashtiradi."""
return unicodedata.normalize("NFC", matn.strip())
print(" Ma'lumotlar bazasiga yozishdan oldin va qidirishda")
print(" normalize() ni qo'llang — muammo yo'qoladi.")=== 1. Bir xil ko'rinish, turli tuzilma ===
Tayyor belgi (NFC): 'é'
Ko'rinishi: é
len(): 1
Kod nuqtalari:
U+000E9 Ll LATIN SMALL LETTER E WITH ACUTE
Qismlardan (NFD): 'é'
Ko'rinishi: é
len(): 2
Kod nuqtalari:
U+00065 Ll LATIN SMALL LETTER E
U+00301 Mn COMBINING ACUTE ACCENT
Teng? False
NFC dan keyin: True
=== 2. Emoji — bir belgi, ko'p kod nuqtasi ===
Oila emojisi: '👨👩👧👦'
len(): 7
...
Kesish muammosi:
To'liq: Salom 👨👩👧👦 dunyo
len(): 19
matn[:8]: Salom 👨 ← emoji buzildi
=== 3. Amaliy: qidiruv muammosi ===
Qidiruv: 'José'
'José' oddiy=True normalizatsiya bilan=True
'José' oddiy=False normalizatsiya bilan=True
'Jose' oddiy=False normalizatsiya bilan=FalseNima ko'rsatdi: 2.8-bo'lim. Bu — foydalanuvchi ismlari va qidiruv bilan ishlaganda haqiqiy muammo.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"len(matn) baytlar sonini beradi" |
Kod nuqtalari sonini. Baytlar uchun .encode() |
| "Har bir belgi 4 bayt" | CPython eng katta kod nuqtasiga qarab 1, 2 yoki 4 bayt tanlaydi |
"a is b satrlar uchun ishlaydi" |
Ba'zan. Internlash — optimizatsiya, kafolat emas |
| "Bitta belgi = bitta kod nuqtasi" | Emoji va urg'uli harflar bir necha kod nuqtasi bo'lishi mumkin |
"matn[0] str emas" |
str. Pythonda alohida char turi yo'q |
| "Satr — belgilar ro'yxati" | O'xshash, lekin o'zgarmas va in pastki satr qidiradi |
| "Emoji qo'shish zararsiz" | Butun satrni 4 baytli rejimga o'tkazadi |
""é" == "é" doim True" |
Turli normalizatsiya shakllarida False bo'lishi mumkin |
6. Keng tarqalgan xatolar va yechimlari
1. IndexError: string index out of range
if matn: # ✅ bo'sh emasligini tekshiring
birinchi = matn[0]
birinchi = matn[:1] # ✅ kesim — xavfsiz2. is bilan satr solishtirish
if kirish is "ha": # ❌ SyntaxWarning, ishonchsiz
if kirish == "ha": # ✅3. TypeError: 'str' object does not support item assignment
matn[0] = "S" # ❌
matn = "S" + matn[1:] # ✅4. Unicode normalizatsiya muammosi
if ism == qidiruv: # ❌
if normalize("NFC", ism) == normalize("NFC", qidiruv): # ✅5. Emoji bilan uzunlik cheklash
qisqa = izoh[:100] # ❌ emoji buzilishi mumkin
# Xavfsizroq — baytlarda cheklash
qisqa = izoh.encode("utf-8")[:400].decode("utf-8", errors="ignore")6. ord() ko'p belgili satrga
ord("ab") # ❌ TypeError: expected a character
ord("a") # ✅
[ord(c) for c in "ab"] # ✅ [97, 98]7. chr() chegaradan tashqarida
chr(1_114_112) # ❌ ValueError
chr(0x10FFFF) # ✅ eng katta8. Katta matnda emoji xotira sarfi
# Millionlab qatorli logda bitta emoji butun buferni 4x qiladi
# Yechim: emoji bo'lgan qatorlarni alohida saqlash yoki
# baytlarda ishlash (16-qism)7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 4.2-dars: kesimlar — indekslashning davomi
- 4.8-dars: Unicode to'liq — kod nuqtalari, tekisliklar, kategoriyalar
- 4.9-dars:
encode/decode— kod nuqtasi ↔ bayt - 4.12-dars: o'zgarmaslik va internlash chuqur
- 5-qism: iteratsiya,
enumerate - 6-qism: satr va ro'yxat o'rtasidagi aylantirish, xeshlash
- 16-qism: fayllar, kodlash, baytlar
- 15-qism: muntazam ifodalar — Unicode kategoriyalari
- 23-qism: ma'lumotlar bazasida matn saqlash (bayt va belgi farqi)
8. Eng yaxshi amaliyotlar
isni satrlar bilan hech qachon ishlatmang. Internlash — optimizatsiya tafsiloti.Foydalanuvchi kiritmasini normallashtiring.
unicodedata.normalize("NFC", matn)— qidiruv va solishtirishda muammoni oldini oladi.len()belgilarni sanashini eslang. Ma'lumotlar bazasi cheklovi baytlarda bo'lishi mumkin.Indeks o'rniga kesim ishlating.
matn[:1]matn[0]dan xavfsizroq.for h in matn:— eng tez iteratsiya.range(len(matn))kerak emas.enumerateindeks kerak bo'lganda.for i, h in enumerate(matn).Emoji va maxsus belgi bilan uzunlik cheklashda ehtiyot bo'ling. Kesish belgini buzishi mumkin.
stringmodulidagi doimiylardan foydalaning.string.ascii_lowercase— qo'lda yozishdan yaxshiroq.
9. Amaliy topshiriq
Vazifa 1: Kod nuqtalari
1. ord("A")
2. ord("a") - ord("A")
3. chr(ord("a") + 25)
4. len("салом")
5. len("салом".encode("utf-8"))
6. ord("😊")
7. len("👨👩👧👦")Javoblar
6532'z'5— belgilar10— kirillitsa UTF-8 da 2 bayt1285227— ZWJ bilan birlashtirilgan
Vazifa 2: Xotira tahlili
1-misoldagi tahlil() funksiyasini ishlatib, quyidagilarni solishtiring:
["hello", "héllo", "hеllo"] # 3-satrda kirilcha 'е'!Nega uchinchisi ko'proq joy egallaydi? (Diqqat: е kirilcha, e lotincha)
Vazifa 3: Sezar shifri
2-misoldagi sezar() ni kengaytiring:
- Kirillitsa harflarini ham qo'llab-quvvatlasin
sindir(shifr)funksiyasini yozing — barcha 26 siljishni sinab ko'rsin- Eng ehtimolli siljishni toping (eng ko'p uchraydigan harf
ayokiebo'lishi kerak)
Vazifa 4: Internlash
a = "test_nom"
b = "test_nom"
c = "test" + "_nom"
qism = "test"
d = qism + "_nom"
e = sys.intern(qism + "_nom")
f = sys.intern("test_nom")Qaysi juftliklar is bo'yicha teng? Oldin bashorat qiling.
Javoblar
a is b→True(ikkalasi ham kompilyatsiya doimiysi, internlangan)a is c→True(kompilyator"test" + "_nom"ni birlashtiradi)a is d→False(ishlash paytida yaratildi)e is f→True(ikkalasi internlangan)a is e→True(aham internlangan)
Vazifa 5: Belgi statistikasi
Funksiya yozing: matndagi har bir belgi kategoriyasi bo'yicha statistika chiqarsin.
belgi_statistikasi("Salom, Dunyo! 123 😊") Lu (katta harf): 2
Ll (kichik harf): 8
Nd (raqam): 3
Zs (bo'sh joy): 3
Po (tinish): 2
So (belgi): 1Yechim
import unicodedata
from collections import Counter
NOMLAR = {
"Lu": "katta harf", "Ll": "kichik harf", "Nd": "raqam",
"Zs": "bo'sh joy", "Po": "tinish", "So": "belgi",
"Lo": "boshqa harf", "Sc": "valyuta",
}
def belgi_statistikasi(matn: str) -> None:
hisob = Counter(unicodedata.category(c) for c in matn)
for kod, soni in hisob.most_common():
nom = NOMLAR.get(kod, "boshqa")
print(f" {kod} ({nom}): {soni}")Counter — 15-qismda o'rganamiz.
Vazifa 6: Normalizatsiya
xavfsiz_solishtir(a, b) funksiyasini yozing:
- Bo'sh joylarni tozalasin
- Kichik harfga o'tkazsin
- NFC normalizatsiya qilsin
- Keyin solishtirsin
Sinang: "José", " josé ", "JOSÉ".
Vazifa 7: O'ylash
Nega CPython satrlarni sobit uzunlikda saqlaydi (1/2/4 bayt), UTF-8 da emas? UTF-8 ixchamroq-ku.
Javob
Indekslash tezligi uchun.
UTF-8 da har bir belgi 1–4 bayt egallaydi. matn[1000] ni topish uchun boshidan sanash kerak bo'lardi — O(n).
Sobit uzunlikda esa oddiy hisob:
manzil = boshlanish + 1000 × bayt_uzunligiBu — O(1).
Solishtiring: Go va Rust satrlarni UTF-8 da saqlaydi va shuning uchun ularda s[i] bayt qaytaradi, belgi emas. Belgi bo'yicha yurish uchun maxsus iterator kerak.
Python soddalikni tanladi: matn[i] doim belgi qaytaradi va tez ishlaydi. Narxi — ba'zan ko'proq xotira.
Bu — 1.5-darsdagi "Soddalik murakkablikdan yaxshi" qoidasining amaliy namunasi.
Nimani mustahkamlaydi: 2.2, 2.3, 2.6, 2.8, 2.9-bo'limlar.
Xulosa
Bu darsda satrning ichki tuzilishini o'rgandik.
Eng muhim uch fikr:
Satr — kod nuqtalari ketma-ketligi.
len()belgilarni sanaydi, baytlarni emas. CPython eng katta kod nuqtasiga qarab 1, 2 yoki 4 bayt tanlaydi — bitta emoji butun satrni 4 barobar kattalashtiradi.Internlash — optimizatsiya, kafolat emas. Identifikatorga o'xshash satrlar avtomatik internlanadi, boshqalari yo'q. Shuning uchun satrlar bilan doim
==, hech qachonis.Ko'rinadigan belgi ≠ kod nuqtasi.
"é"bir yoki ikki kod nuqtasi bo'lishi mumkin. Foydalanuvchi kiritmasiniunicodedata.normalize("NFC", ...)bilan normallashtiring.
Keyingi darsda kesimlarni (slicing) chuqur o'rganamiz: slice obyekti, salbiy qadam, kesim bilan o'zlashtirish va eng foydali idiomalar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!