Python ile Anagram oluşturma

Merhaba dostlar.

Bugün, akşamüstü vakitlerinde Google’da “Python örnek kodlar” ve “Python örnekleri” diye arattırdım. Sonuçlar içerisinde bir web sitesine denk geldim ve Python ile Anagram (Bkz. Anagram Nedir?) oluşturduğunu iddia eden bir makale okudum. Mantık olarak çok az doğru gidilse de istenilen sonuca ulaşması imkansızdı iddia edilen makalede. Çünkü pek çok detay atlanmış ve düzensiz bir değer ortaya çıkıyordu. Bende emin olmak için kendim yapmaya karar verdim.

Yazının sonlarına doğru, Anagram tekniğinin doğru algoritmasını ve bunun kodlarını göreceksiniz. Ama “Ben hepsini okuyamam, kodu görsem anlarım arkadaş! Sen sadece kodları ver” diyorsan, tıkla bakalım.

Şimdi bahsettiğim web sitesini ve yukarıda yazdıklarımı bir kenara bırakıp; TÜBİTAK’ın yayınlamış olduğu aşağıdaki soruları nasıl cevaplarız, buna odaklanalım.

Görüntü 011
(Kaynak: TÜBİTAK UEKAE)

 

Önce algoritmayı ele alalım ve neyin ne ifade ettiğini bir kavrayalım.

Anagram tekniğinde; belirtilen cümle veya kelime içerisinde kaç adet harf olduğu tespit edilir ve ardından boşluk karakterler dikkate alınmaksızın, bulunan sonuç alfabetik sıraya alınarak yazılır. Örneğin “merhaba” kelimesini ele alalım. Kelime içerisindeki harfleri, adetleri ile beraber vermiş olduğumuz kelime bazında sıralayacak olursak şu sonuçları elde ederiz (Tablo 1).

Tablo 1: "merhaba" kelimesindeki harfler ve kaç adet olduğunun gösterilmesi
Tablo 1

Yukarıda Anagram için bulunan harf ve adetlerde alfabetik sıralama yaptığından da bahsetmiştik. Tablo 1’deki verileri alfabetik sıralamaya alacak olursak şöyle bir sonuç alacağız, “2a1b1e1h1m1r”.

Peki bu sonuç yeterli mi? Cevap kesinlikle hayır! Çünkü Anagram tekniğinde kodlanacak olan kelime veya cümle içerisindeki harflerden sadece bir tane varsa, sayısal değeri yazılmaz. Haliyle sonucumuz “2abehmr” şeklinde olmalıdır.

Bu nereden anlıyoruz?
TÜBİTAK’ın vermiş olduğu örneği tekrar inceleyelim. “Dünya güneşin etrafında döner” cümlesini ele alalım. İçerisindeki harfleri alfabetik bazında sıralayacak olursak, sonuç aşağıdaki gibi olacaktır (Tablo 2).

Tablo 2: "Dünya güneşin etrafında döner" kelimesindeki harfler ve kaç adet olduğunun gösterilmesi
Tablo 2

Tablo 2’yi tek satırlık bir düzene sokacak olursak bizim bulduğumuz sonuç “3a3D3e1f1g1ı1i5n1ö2r1ş1t2ü1y” şeklinde olacaktır. Peki TÜBİTAK’ın bu soruya vermiş olduğu cevap neydi? Sayfanın en başına gelerek bakıyoruz, bize verdiği cevap, “3a3d3efgıi5nö2rşt2üy” olarak belirtilmiş. Buradan iki sonuç çıkar:

  1. Dikkat ederseniz kelime içerisindeki f,g,ı,i,ş,y harflerinin başında 1 yazmamaktadır, yani sayısal değerini belirtmemiştir. Bu demek oluyor ki, kelime veya cümle içerisindeki tek harfler için sayısal değerini yazmamalıyız.
  2. Bulduğumuz sonuç ile TÜBİTAK’ın bulduğu sonuç arasında bir harf farkı vardır. “Dünya güneşin etrafında döner” cümlesindeki “D” harfi büyüktür. Bulduğumuz sonuç içerisinde “D” büyük iken, TÜBİTAK’ın verdiği sonuç içerisindeki “d” harfi küçüktür. Bu demek oluyor ki, kelime veya cümle içerisindeki harflerin hepsini küçük harf olarak dikkate almalıyız.

 

Buraya kadar Anagram tekniğinin inceliklerini fark etmişsinizdir.

Şimdi, Python’da yazdığım kodları ve bulduğu sonuçları paylaşıyorum. Detaylı anlatım devam edecektir..

Python ile TÜBİTAK sorusunun cevabını bulan kod.

# -*- coding: cp1254 -*-
__author__ = 'EnisKurtay'
import locale
locale.setlocale(locale.LC_ALL, "Turkish_Turkey.1254")
 
def anagram(cumle):
    cumle = cumle.lower()
    liste = []
    for s in set(cumle):
        if (str(s).isspace() == False) and (str(s).isalpha() == True):
            liste.append(s)
    liste.sort(key = locale.strxfrm)
 
    if (liste.__contains__("ı") == True) and (liste.__contains__("i") == True):
        liste.remove("i")
        liste.insert(liste.index("ı") + 1,"i")
 
    sonuc = ""
    for d in liste:
        if cumle.count(d) == 1:
            sonuc = sonuc + "{0}".format(d)
        else:
            sonuc = sonuc + "{0}{1}".format(cumle.count(d), d)
    return sonuc
 
#Birinci sorunun cevabı
print "TÜBİTAK Cevapları..\n(i) : {0}".format(anagram("Dünya güneşin etrafında döner"))
 
#Ikinci sorunun cevabı
tubitakCumleler = ["Su molekülünde üç atom vardır", "Yanma oksijen gerektirir", "Elmas karbondan oluşur"]
for s in tubitakCumleler:
    if anagram(s) == "2a3eg3ij2km2no3rsty":
        print "(ii): {0}".format(s)

Bulduğumuz cevabı da kanıtlayalım.

Görüntü 015


Detaylı Anlatım

Öncelikle anagram adında bir parametrik fonksiyon tanımladım:

def anagram(cumle):

Ardından “cumle” parametresine gelecek değeri, içerisinde bulunan harfleri tekrarlamayacak şekilde döngüye alıp bir listeye aktarıyorum. Fakat listeye aktarmadan önce, gelen değerin harf mi yoksa boşluk karakteri mi olduğuna dikkat ederek listeye aktarıyorum. Hemen bunun sonrasında bu listeyi alfabetik olarak sıralıyorum.

    cumle = cumle.lower()
    liste = []
    for s in set(cumle):
        if (str(s).isspace() == False) and (str(s).isalpha() == True):
            liste.append(s)
 
    #Aşağıdaki sort() fonksiyonun içerisindeki parametreyi birazdan açıklayacağım
    liste.sort(key = locale.strxfrm)

Ancak burada bir şey dikkatimi çekmişti, sizlerle paylaşmak isterim. Python ile Türkçe’de bulunan tüm harfleri içeren bir diziyi sıralamaya doğrudan aldığımda, Türkçe’de bulunan işaretli (ç, ö, ü, ş gibi) karakterlerin sıralamada en sonlarda belirdiğini gözlemledim. İnternette locale kullanarak türkçe karakterli işlemlerde setlocale yapmamız gerektiğini belirten bir yazıyla karşılaştım. Bu yüzden önce locale tanımlarımı yaptım ve ardından sort() fonksiyonun içerisinde böyle bir parametre yazdım.

locale ettikkten sonra herşeyin düzenli ancak “i” harfinin, “ı” harfinden önce geldiğini gördüm. İnternette bu sefer tam bir derinlemesine araştırma yaptım ve bunun çözümü ile alakalı pek çok şey okudum. Hiçbiri istediğim sonucu vermedi. UTF-8, Unicode yöntemleriyle çözmeye çalışıyorlardı fakat bana Windows – 1254 gerekiyordu. Düşünsenize bir kelime içerisindeki harfleri alfabetik sıraya soktunuz ve “cç”, “gğ”, “oö”, “sş”, “uü” harfleri düzenli & doğru gelirken, “iı” düzensiz geliyor(!) Tam bir saçmalık ve kabul edilemez bir durum!

Bende daha fazla vakit harcamamak ve bunun önüne geçmek için kısa bir çözüm buldum. Eğer bulduğum kelimelerin içerisinde “ı” ve “i” harfleri varsa, yerlerini değiştirmem benim için yeterliydi. Çünkü “ı” harfi yoksa, mantıklı olarak “i” harfi aslında olması gereken yerdedir alfabetik sıralamada. 🙂

if (liste.__contains__("ı") == True) and (liste.__contains__("i") == True):
        liste.remove("i")
        liste.insert(liste.index("ı") + 1,"i")

Ardından fonksiyonumuzun geri kalanını yazdım. Aşağıdaki kodlarda her harfin, kaç adet olduğunun bilgisini değişkene ekleyerek, fonksiyon içerisinde bulduğum sonucu “return” deyimi döndürdük.

sonuc = ""
    for d in liste:
        if cumle.count(d) == 1:
            sonuc = sonuc + "{0}".format(d)
        else:
            sonuc = sonuc + "{0}{1}".format(cumle.count(d), d)
    return sonuc

Geriye artık fonksiyonumuzu çağırmak kaldı. Tek yapmamız gereken fonksiyonu çağırırken içine parametre vermektir. Bende TÜBİTAK’ın verdiği soruları çözen kodları yazdım. Eğer siz sadece Anagram’daki değeri görmek istiyorsanız ‘print anagram(“cümle veya kelimenizi buraya yazın”)‘ demeniz yeterlidir.

#Birinci sorunun cevabı
print "TÜBİTAK Cevapları..\n(i) : {0}".format(anagram("Dünya güneşin etrafında döner"))
 
#Ikinci sorunun cevabı
tubitakCumleler = ["Su molekülünde üç atom vardır", "Yanma oksijen gerektirir", "Elmas karbondan oluşur"]
for s in tubitakCumleler:
    if anagram(s) == "2a3eg3ij2km2no3rsty":
        print "(ii): {0}".format(s)

Bir sonraki makalede görüşmek üzere.

Bu makalede geçen kodlar için : https://github.com/eniskurtayyilmaz/Python27/blob/master/anagram.py
Enis Kurtay YILMAZ

Python ile temel dosya işlemleri

Merhaba dostlar.
Bugünkü makalede Python programlama dili ile temel dosya işlemlerini, yeni öğrenenler açısından basit düzeyde gerçekleştireceğiz.

Programlama ile uğraşıyorsanız, er yada geç uğraşacağınız şeyden biri de dosyalardır. Dosyalar içerisinde yapmak isteyeceğiniz işlemlerdir. Bir dosya içerisine veri yazmak veya okumak olabilir bunlar. Bunun için “IO” (input and output) bileşenini kullanmanız gerekmektedir. Bir dosya ile bağlantı kurmak için önce open() fonksiyonunu kullanacağız. Python ile hadi kodlayalım!

dosya = open("yazi.txt", "w")

Yukarıdaki örnekte çalıştığınız dizin üzerinde “yazi.txt” dosyası ile bağlantıyı dosya değişkenine aktararak bağlantısını gerçekleştiriyoruz. Eğer çalıştığınız dizin üzerinde “yazi.txt” diye bir dosya yoksa yeni bir tane oluşturacaktır. Bunun sebebi ise IO bileşeni içerisindeki tanımlanmış mode’tur. Yukarıda “w” yazdığımız yer, aslında bizim tanımladığımız bir mode. Dosya içerisine yazı yazabileceğimizi belirtir.

Modlardan genel olarak bahsedelim biraz. Aslında mode, bir dosya ile yapacağımız işlemden önce erişim tanımlamaktır. Örneğin bir dosyayı sadece okuma işlemleri için modunu “r” yapmamız (read/okuma) yeterlidir. Bu sayede ilgili dosya ile sadece okuma işlemi yapacağımızı belirtmiş oluruz. Doğal olarak okuma modunda açtığımız için, üzerine yazma gibi bir durumumuz söz konusu değildir. Biraz onlardan ve özelliklerinden bahsedelim bahsedelim bu esnada.

Mode Tanım & Açıklama
“r” Read/Okumak anlamına gelir. Bu Mode ile sadece okuma işlemleri yapılır. Eğer böyle bir mode tanımlamış ve ileriki kodunuzda yazma işlemi yapmaya çalıştığınızda hata alırsınız.

Eğer belirttiğiniz dizinde dosya yok ise, hata alırsınız.

“w” Write/Yazmak anlamına gelir. Bu mode ile yazma işlemi yapılır. Eğer belirttiğiniz dizinde dosya yok ise, yeni dosya yaratır.

Eğer belirttiğiniz dizinde dosya var ise önce içindekini siler, ardından tekrardan yeni dosya yaratır.

Örneğin a.txt dosyası içerisinde “Merhaba” yazıyor olsun. Yeni bir “Naber” satırı yazma işlemi gerçekleştirdiğinizde, dosyanız aşağıdaki gibi gözükür.

Naber

“a” Append/Eklemek anlamına gelir. Bu Mode ile mevcut olanın üzerine eklemeler yapar. Eğer belirttiğiniz dizinde dosya yok ise, yeni dosya yaratır.

Eğer belirttiğiniz dizinde dosya var ise dosya içerisindeki yazanlara bir hamlede bulunmaz, yazacağınız yeni içeriği dosyaya ilave eder.

Örneğin a.txt isminde bir dosyanız olsun içerisinde “Merhaba” yazıyor olsun. Siz “a” modunda bağlanıyorsanız ve dosya içerisine yeni bir “Naber” satırı yazma işlemi gerçekleştirdiğinizde, dosyanız aşağıdaki gibi gözükür.

Merhaba
Naber

Bu modlara ek olarak, “w+”, “a+” gibi tanımlarda vardır. Temel anlamda gittiğimiz için başka bir makalede bunlardan bahsedeceğim.

Şimdi Python ile yazi.txt diye bir dosya oluşturalım ve ardından “merhaba\nnaber” yazdıralım. Bildiğiniz üzere “\n” kaçış dizisi ile “naber” yazısının bir alt satıra inmesini sağlayacağız.

dosya = open("yazi.txt","w")
dosya.write("merhaba\nnaber")
dosya.close()

Yukarıdaki kod ile yazi.txt adında bir dosya oluşturuyoruz, tanımladığımız “w” mode ile. Ardından write() fonksiyonunu alt alta gelecek şekilde yazımızı yazdırıyoruz. Dosyaya girip, baktığınızda aşağıdaki gibi gözükecektir.

merhaba
naber

En sondaki close() fonksiyonu ise bu dosya ile işimizin bittiğini, mevcut bağlantının ise sonlandırılmasını belirtiyoruz.

Peki mevcut olan bu dosyayı nasıl okutturabiliriz?

dosya = open("yazi.txt","r")
icerik = dosya.read()
dosya.close()
print satir

Yukarıda fark ettiyseniz, “r” yani okuma modunda dosyaya bağlandım. Ardından icerik adındaki değişkene, read() fonksiyonunu kullanarak dosya içerisindeki tüm verileri aktardım, dosya bağlantısını sonlandırdım. Son satırda da icerik adındaki değişkenin içerisindekini ekrana yazdırdım. Karşınıza aşağıdaki sonuç çıkacaktır.

merhaba
naber

Son bir örnek daha yapalım, bu sefer “a” modunda olsun yani mevcut olanın üzerine eklemeler yapalım “Append” ile.

dosya = open("yazi.txt","a")
dosya.write("iyi senden naber?")
dosya.close()

Bu sefer modu “a” yaptık ve dosya içerisine “iyi senden naber?” yazdık. Ardından mevcut bağlantıyı sonlandırdık.

Peki dosya içerisine girdiğimizde ne görmüş olacağız, ona da bakalım dilerseniz. Aşağıdaki gibi veriler gösterilecektir.

merhaba
naberiyi senden naber?

“naber” ve “iyi senden naber?” neden yanyana oldu? Çünkü kaçış dizisi veya boşluk kullanmadığımız için böyle bir şey gerçekleşti. Yukarıda kaçış dizisini hatırlamışsınızdır “\n” şeklindeydi.

Burası önemli! Çünkü buradan bir sonuç daha çıkarabiliriz. Demek ki write() fonksiyonu satır satır yazmıyor. İmlecin son durduğu yerden yazmaya başlıyor demektir. İpucu isterseniz, alt satıra geçmek için “\n” kaçış dizilerini kullanabiliriz.

Bir sonraki makalede görüşmek dileğiyle.

K. YILMAZ