Ek: 8. hafta ev alıştırmaları

8. hafta ev alıştırmaları: string işlemleri

Bu sayfadaki sekiz alıştırma String işlemleri bölümünün konularıyla kod yazdırır. Alıştırmalar kolaydan zora sıralı. İlk dördü bölümdeki örneklere çok benzer, son dördü birkaç konuyu bir arada kullanır.

Her alıştırma aynı düzende:

  • Ne yapacaksınız? Yazacağınız kodun işini anlatır.
  • Nerede işinize yarar? Bu işin gerçek bir programda nerede karşınıza çıkacağını söyler.
  • Doğru olduğunu nasıl anlarsınız? Beklenen çıktıyı ya da hücrenin sonundaki assert satırlarını gösterir. Hücre hata vermeden Kontroller tamamlandı yazarsa çözümünüz denemelerin hepsini geçmiştir.

Kodu hücrenin içine yazın ve Run Code düğmesine basın. Hücrenin altında kodunuzu deneyen bir geri bildirim de çıkar. Takılırsanız önce ipucunu açın. Çözümü, kendi kodunuz çalıştıktan sonra karşılaştırmak için açın. Yazdığınız kod tarayıcınızda saklanır: sayfayı kapatıp açtığınızda kaldığınız yerden devam edersiniz.

1. Kulüp duyurusu

Ne yapacaksınız? Aşağıdaki üç satırlık duyuruyu tek bir print() ile yazdırın. Satırları \n ile ayırın. Gün: ve Saat: yazılarından sonra boşluk yerine \t kullanın.

Kodlama kulübü
Gün:    Salı
Saat:   14.00

Nerede işinize yarar? Bir mesajı, fişi ya da raporu tek string olarak hazırlayıp bir kerede yazdırmak ya da dosyaya kaydetmek sık yapılan bir iştir. 12. haftada dosyaya yazarken satırları yine \n ile ayıracaksınız.

Doğru olduğunu nasıl anlarsınız? Çıktınız yukarıdaki üç satırla aynı olmalı. Salı ve 14.00 aynı hizada başlamalı.

Bütün duyuru tek bir string’in içinde durur: "Kodlama kulübü\nGün:\t..." diye devam edin.

print("Kodlama kulübü\nGün:\tSalı\nSaat:\t14.00")

2. Ders kodunu açıklamak

Ne yapacaksınız? Okuldaki ders kodları altı karakterlidir: ilk üç harf bölümü, dördüncü karakter sınıfı, son iki karakter dersin sırasını gösterir. BLP101 kodu, BLP bölümünün 1. sınıf derslerinden 01 numaralı derstir. ders_kodu_aciklama(kod) adlı fonksiyonu yazın. Fonksiyon kodu dilimlere ayırsın ve şu biçimde bir string döndürsün:

Bölüm: BLP, sınıf: 1, sıra: 01

Nerede işinize yarar? Öğrenci numarası, ürün kodu, plaka ya da fatura numarası gibi değerlerin her parçası bir bilgi taşır. Parçaları dilimle ayırmak bu bilgileri okumanın ilk adımıdır.

Doğru olduğunu nasıl anlarsınız? Hücrenin sonundaki üç assert geçmeli.

Bölüm kod[:3], sınıf kod[3], sıra kod[4:]. Üçünü f"Bölüm: {...}, sınıf: {...}, sıra: {...}" içine yerleştirin.

def ders_kodu_aciklama(kod):
    bolum = kod[:3]
    sinif = kod[3]
    sira = kod[4:]
    return f"Bölüm: {bolum}, sınıf: {sinif}, sıra: {sira}"

assert ders_kodu_aciklama("BLP101") == "Bölüm: BLP, sınıf: 1, sıra: 01"
assert ders_kodu_aciklama("MAT205") == "Bölüm: MAT, sınıf: 2, sıra: 05"
assert ders_kodu_aciklama("TDL112") == "Bölüm: TDL, sınıf: 1, sıra: 12"

print("Kontroller tamamlandı")

3. PDF dosyası mı?

Ne yapacaksınız? Ödev sistemine yalnız PDF dosyası yüklenebiliyor. pdf_mi(dosya) adlı fonksiyonu yazın. Fonksiyon dosya adının PDF olup olmadığına bakıp True ya da False döndürsün. Dosya adları kullanıcıdan geldiği için başında ya da sonunda boşluk ve satır sonu olabilir, uzantı büyük harfle yazılmış olabilir.

Nerede işinize yarar? Bir dosyayı açmadan önce türüne bakmak bütün dosya programlarının ilk işidir. Bölümdeki rapor.pdf.txt tuzağını da burada kendiniz yakalayacaksınız.

Doğru olduğunu nasıl anlarsınız? Beş assert geçmeli. Özellikle dördüncüsüne dikkat edin: adın içinde .pdf geçiyor ama dosya PDF değil.

Temizlik için strip() ve lower(), karar için endswith(".pdf") yeter. ".pdf" in dosya dördüncü denemede yanlış sonuç verir.

def pdf_mi(dosya):
    temiz = dosya.strip().lower()
    return temiz.endswith(".pdf")

assert pdf_mi("rapor.pdf") == True
assert pdf_mi("  Odev.PDF ") == True
assert pdf_mi("sunum.pdf\n") == True
assert pdf_mi("rapor.pdf.txt") == False
assert pdf_mi("pdf_notlari.docx") == False

print("Kontroller tamamlandı")

4. Telefon numarasını temizlemek

Ne yapacaksınız? Kayıt formundaki telefon alanına herkes farklı yazıyor: 0555 123 45 67, 05551234567, 0555 1234567. İki fonksiyon yazın:

  • telefon_temizle(metin): Uçlardaki boşluğu ve satır sonunu, aradaki boşlukları silip numarayı döndürür.
  • telefon_gecerli_mi(numara): Temizlenmiş numara 11 karakterse, 05 ile başlıyorsa ve yalnız rakamlardan oluşuyorsa True döndürür.

Numarayı int() ile sayıya çevirmeyin: baştaki 0 kaybolur. Telefon numarası hesap yapılacak bir sayı değil, rakamlardan oluşan bir metindir.

Nerede işinize yarar? Aynı numara üç farklı yazımla kaydedilirse arama yaparken bulunamaz. Veriyi kaydetmeden önce tek biçime getirmek bu sorunu önler.

Doğru olduğunu nasıl anlarsınız? Altı assert geçmeli.

telefon_temizle için metin.strip().replace(" ", "") yeter. telefon_gecerli_mi üç koşulu and ile birleştirir: len(numara) == 11, numara.startswith("05"), numara.isdigit().

def telefon_temizle(metin):
    return metin.strip().replace(" ", "")

def telefon_gecerli_mi(numara):
    return len(numara) == 11 and numara.startswith("05") and numara.isdigit()

assert telefon_temizle(" 0555 123 45 67\n") == "05551234567"
assert telefon_temizle("0555 1234567") == "05551234567"
assert telefon_gecerli_mi("05551234567") == True
assert telefon_gecerli_mi("5551234567") == False
assert telefon_gecerli_mi("0555123456a") == False
assert telefon_gecerli_mi("04441234567") == False

print("Kontroller tamamlandı")

5. Kantin fişi

Ne yapacaksınız? Kantindeki kasa programı fişe her ürün için bir satır yazıyor. fis_satiri(urun, adet, birim_fiyat) adlı fonksiyonu yazın. Fonksiyon satır tutarını (adet * birim_fiyat) hesaplasın ve tutarı iki ondalık basamakla gösteren bir string döndürsün:

Simit x3 = 22.50 TL

Fonksiyon satırı yazdırmasın, döndürsün. Yazdırma işi fonksiyonu çağıran koda kalır.

Nerede işinize yarar? Para tutarları ekranda hep iki basamakla gösterilir: 22.5 TL değil 22.50 TL. Hesap ile gösterim ayrıdır: tutar float olarak kalır, yalnız yazılırken biçimlenir.

Doğru olduğunu nasıl anlarsınız? Üç assert geçmeli, hücre fişin üç satırını da yazdırmalı.

Önce tutar = adet * birim_fiyat yazın. Sonra f"{urun} x{adet} = {tutar:.2f} TL" değerini döndürün.

def fis_satiri(urun, adet, birim_fiyat):
    tutar = adet * birim_fiyat
    return f"{urun} x{adet} = {tutar:.2f} TL"

assert fis_satiri("Simit", 3, 7.5) == "Simit x3 = 22.50 TL"
assert fis_satiri("Ayran", 2, 12) == "Ayran x2 = 24.00 TL"
assert fis_satiri("Tost", 1, 45.25) == "Tost x1 = 45.25 TL"

print(fis_satiri("Simit", 3, 7.5))
print(fis_satiri("Ayran", 2, 12))
print(fis_satiri("Tost", 1, 45.25))

6. Baş harfler

Ne yapacaksınız? Yaka kartlarına öğrencinin baş harfleri yazılacak. bas_harfler(ad_soyad) adlı fonksiyonu yazın. Fonksiyon adı sözcüklerine ayırsın, her sözcüğün ilk harfini büyütüp arkasına nokta koysun ve hepsini birleştirip döndürsün: "deniz yılmaz" için "D.Y.".

Sonucu bir döngüde adım adım biriktireceksiniz. 5. haftadaki toplam biriktirmenin aynısı, yalnız sayı yerine string: boş bir string’le başlayın, her turda + ile yeni harfi ekleyin.

Nerede işinize yarar? Ad, adres ya da cümle gibi metinleri sözcüklerine ayırıp her sözcükle ayrı iş yapmak metin işlemenin en sık kalıbıdır.

Doğru olduğunu nasıl anlarsınız? Üç assert geçmeli. İkincisinde adın çevresinde ve sözcüklerin arasında fazladan boşluk var.

for sozcuk in ad_soyad.split(): yazın. Döngüde sonuc = sonuc + sozcuk[0].upper() + "." satırı yeter. Argümansız split() fazladan boşlukları kendisi atar.

def bas_harfler(ad_soyad):
    sonuc = ""
    for sozcuk in ad_soyad.split():
        sonuc = sonuc + sozcuk[0].upper() + "."
    return sonuc

assert bas_harfler("deniz yılmaz") == "D.Y."
assert bas_harfler("  ali   can ") == "A.C."
assert bas_harfler("Ece Nur Şahan") == "E.N.Ş."

print("Kontroller tamamlandı")

Fonksiyonunuz I.A. döndürür, oysa beklenen İ.A.’dır. upper() Türkçe kurala uymaz: i harfini noktasız I yapar. Bölümdeki turkce_kucult() fonksiyonunun tersini yazarak düzeltebilirsiniz:

def turkce_buyut(metin):
    return metin.replace("i", "İ").replace("ı", "I").upper()

Döngüdeki upper() yerine turkce_buyut() çağırın.

7. Şifre kuralı

Ne yapacaksınız? Kulübün sitesinde şifre üç kurala uymalı: en az 8 karakter olmalı, en az bir rakam içermeli, boşluk içermemeli. sifre_uygun_mu(sifre) adlı fonksiyonu yazın. Üç kurala da uyan şifre için True, birine bile uymayan için False döndürsün.

Rakam kuralı için şifrenin karakterlerini döngüyle gezin ve rakamları sayın. Bölümdeki karakter in "0123456789" denetimini kullanabilirsiniz.

Nerede işinize yarar? Kullanıcıdan gelen metni bir kurala göre denetlemek, form doğrulamanın temelidir. 3. haftadaki girdi doğrulamanın metin üzerindeki hâlidir.

Doğru olduğunu nasıl anlarsınız? Beş assert geçmeli. Her yanlış şifre ayrı bir kuralı bozuyor.

Önce rakam_sayisi = 0 yazıp döngüde rakamları sayın. Döngüden sonra her kural için bir if yazın: kural bozuluyorsa return False. Üç if de geçilirse en sonda return True gelir.

def sifre_uygun_mu(sifre):
    rakam_sayisi = 0
    for karakter in sifre:
        if karakter in "0123456789":
            rakam_sayisi = rakam_sayisi + 1

    if len(sifre) < 8:
        return False
    if rakam_sayisi == 0:
        return False
    if " " in sifre:
        return False
    return True

assert sifre_uygun_mu("kedi2024") == True
assert sifre_uygun_mu("12345678") == True
assert sifre_uygun_mu("kedi24") == False      # kısa
assert sifre_uygun_mu("kedikedi") == False    # rakam yok
assert sifre_uygun_mu("kedi 2024") == False   # boşluk var

print("Kontroller tamamlandı")

8. Kayıt listesini işlemek

Ne yapacaksınız? Bölümün “Hepsi bir arada” kısmındaki kayıt programını bir fonksiyona dönüştürün. kayit_isle(satir) adlı fonksiyon bir kayıt satırı alsın ve:

  • Okul adresiyle (@omu.edu.tr ile biten) kaydolan için Deniz Yılmaz (2023 girişli) biçiminde bir string,
  • Başka adresle kaydolan için Kabul edilmedi

döndürsün. Fonksiyon yazdırmasın, döndürsün.

Hücrenin sonundaki kod listenin tamamını işliyor. Liste üç tırnaklı tek bir string olarak duruyor. liste.split("\n") onu satırlara ayırıyor, döngü de her satırı fonksiyonunuza veriyor. Bu kısmı değiştirmenize gerek yok. Döngünün bir listeyi gezmesini gelecek hafta ayrıntısıyla göreceğiz.

Nerede işinize yarar? 12. haftada bir dosyayı satır satır okuyup her satırı böyle bir fonksiyona vereceksiniz. Dosyadan gelen satırların sonunda \n bulunur. Son assert bu durumu deniyor.

Doğru olduğunu nasıl anlarsınız? Beş assert geçmeli. Ardından hücre listedeki beş kaydın sonucunu alt alta yazmalı.

Bölümdeki programı fonksiyonun içine taşıyın. İki print() satırını return yapın. satir.split(",") ile başlayın ve üç parçanın her birine strip() uygulayın.

def kayit_isle(satir):
    parcalar = satir.split(",")
    ad = parcalar[0].strip()
    numara = parcalar[1].strip()
    eposta = parcalar[2].strip().lower()

    if eposta.endswith("@omu.edu.tr"):
        yil = "20" + numara[:2]
        return f"{ad} ({yil} girişli)"
    return "Kabul edilmedi"

assert kayit_isle("Işıl Kaya,2406044,[email protected]") == "Işıl Kaya (2024 girişli)"
assert kayit_isle("Deniz Yılmaz, 2306012 ,[email protected]") == "Deniz Yılmaz (2023 girişli)"
assert kayit_isle("Ali Can,2506101,[email protected]") == "Kabul edilmedi"
assert kayit_isle("Ece Şahan,2506077,[email protected]") == "Ece Şahan (2025 girişli)"
assert kayit_isle("Mert Ak,2406090,[email protected]\n") == "Mert Ak (2024 girişli)"

liste = """Işıl Kaya,2406044,[email protected]
Deniz Yılmaz, 2306012 ,[email protected]
Ali Can,2506101,[email protected]
Ece Şahan,2506077,[email protected]
Mert Ak,2406090,[email protected]"""

for satir in liste.split("\n"):
    print(kayit_isle(satir))
Başa dön