Category Archives: Python

Python’da REGEX, örnek


python

import os, re
dosyalar = os.listdir(os.getcwd())
#klasördeki dosyaları listeliyoruz
derle = re.compile("(\{[A-Z].*\})")
for dosya in dosyalar:
#her dosya için
    file = open(dosya, "r") #aç
    liste = file.readlines()
#oku, liste olarak kaydet
    file.close() #kapat
    for s in liste:
#listedeki her satır
#(altyazı satırları oluyor)
        nesne = derle.search(s)
#regex'i ara
        if nesne:
#eğer bulursan(True dönecek)
           a = liste[liste.index(s)]
           a = a.replace(nesne.group(1),"")
           liste[liste.index(s)] = a
#bulduğun kısmı sil
    yeni = open("yeni_%s" % dosya, "w")
#başına "yeni_" ekleyerek
#yeni dosya oluştur
    yeni.writelines(liste)
#yeni dosyaya yaz
    yeni.close()
#yeni dosyayı kaydet
Reklamlar

12. ascii, unicode ve Python


python

Not: Burada verilen bilgiler, len() Fonksiyonu ve ascii’nin Laneti adlı makalede anlatılanlarla birlikte değerlendirilmelidir. Bu belge ve oradaki makale birbirini tamamlayıcı bilgiler içermektedir. Söz konusu makalede temel düzeyde bilgiler verilmekte, burada ise konunun ayrıntılarına inilmektedir.

12.1. Giriş

Orada burada mutlaka Python’un varsayılan kod çözücüsünün ascii olduğuna dair bir cümle duymuşsunuzdur.

Yine sağda solda Python’un unicode’yi desteklediğine dair bir cümle de duymuş olmalısınız.

O halde bu “ascii” ve “unicode” denen şeylerin ne olduğunu da merak etmişsinizdir.

Ben şimdi size burada işin teknik kısmına bulaşmadan hem “ascii”, hem de “unicode” ile ilgili çok kaba bir tarif vereceğim:

“ascii”, Türkçe’ye özgü “ş”, “ç”, “ö”, “ğ”, “ü” ve “ı” gibi harfleri tanımayan bir karakter kodlama biçimidir.

“unicode” ise Türkçe’ye özgü harflerle birlikte dünya üzerindeki pek çok dile ait harfleri de tanıyabilen karakter kodlama biçimlerini içeren, gelişmiş bir sistemdir.

Esasında “unicode”, karakter kodlarını gösteren büyük bir listeden ibarettir. Bu liste içinde dünyadaki (hemen hemen) bütün dillere ait karakterler, simgeler, harfler, vb. yer alır. Aynı şekilde ascii de karakter kodlarını içeren bir listedir. Ancak ascii listesi sadece 128 karakterden oluşurken, unicode yüz binlerce karakteri temsil edebilir.

İşte biz bu makalede, her yerde karşımıza çıkan bu “ascii” ve “unicode” kavramlarını anlamaya, bu kavramların Python’daki yerini ve Python’da ne şekilde kullanıldığını öğrenmeye çalışacağız.

Önce ascii’den başlayalım…
12.2. ascii

Ne kadar gelişmiş olurlarsa olsunlar, bugün kullandığımız bilgisayarların anladığı tek şey sayılardır. Yani mesela “karakter”, “harf” ve “kelime” gibi kavramlar bir bilgisayar için hiçbir şey ifade etmez. Örneğin ekranda gördüğümüz “a” harfi özünde sadece bir sayıdan ibarettir. Bilgisayar bunu “a” harfi şeklinde değil, bir sayı olarak görür. Dolayısıyla, ekranda gördüğümüz bütün harfler ve simgeler makine dilinde bir sayı ile temsil edilir. İşte bu her karakteri bir sayıyla temsil etme işlemine “karakter kodlama” (character encoding) adı verilir. Her bir karakter bir sayıya karşılık gelecek şekilde, bu karakterleri ve bunların karşılığı olan sayıları bir araya toplayan sistematik yapıya ise “karakter kümesi” (charset – character set) denir. Örneğin ascii, unicode, ISO-8859, vb. birer karakter kümesidir. Çünkü bunlar her biri bir sayıya karşılık gelen karakterleri bir arada sunan sistematik yapılardır. Biraz sonra bu sistemleri daha detaylı bir şekilde incelediğimizde tam olarak ne demek istediğimizi gayet net anlayacaksınız.

1960’lı yıllara gelininceye kadar, “yazı yazmaya yarayan makineler” üreten her firma, farklı karakterlerin farklı sayılarla temsil edildiği karakter kümeleri kullanıyordu. Bu karmaşıklığın bir sonucu olarak, herhangi bir makinede oluşturulan bir metin başka bir makinede aynı şekilde görüntülenemiyordu. Çünkü örneğin “a” harfi bir makinede falanca sayı ile temsil edilirken, başka bir makinede filanca sayı ile temsil ediliyordu. Hatta aynı üreticinin farklı model makinelerinde dahi bir bütünlük sağlanmış değildi… Dolayısıyla her üretici kendi ihtiyaçlarına uygun olarak farklı bir karakter kümesi kullanıyordu…

Bu dağınıklığı önlemek ve “yazı makinelerinde” bir birlik sağlamak için American Standards Association (Amerikan Standartları Birliği) tarafından American Standard Code for Information Interchange (Bilgi Alışverişi için Amerikan Standart Kodu) adı altında bir standartlaşma çalışması yürütülmesine karar verildi. İşte “ascii” bu “American Standard Code for Information Interchange” ifadesinin kısaltmasıdır. Bu kelime “askii” şeklinde telaffuz edilir…

İlk sürümü 1963 yılında yayımlanan ascii 7-bitlik bir karakter kümesidir. Dolayısıyla bu küme içinde toplam 27 = 128 adet karakter yer alabilir, yani bu sistemle sadece 128 adet karakter kodlanabilir. (Eğer “7-bit” kavramı size yabancı ise okumaya devam edin. Biraz sonra bu kavramı açıklayacağız.)

Bu bahsettiğimiz 128 karakteri içeren ascii tablosuna (yani “ascii karakter kümesine”) http://www.asciitable.com/ adresinden erişebilirsiniz. Buradaki tablodan da göreceğiniz gibi, toplam 128 sayının (0’dan başlayarak) ilk 33 tanesi ekranda görünmeyen karakterlere ayrılmıştır. Bu ilk 33 sayı, bir metnin “akışını” belirleyen “sekme”, “yeni satır” ve benzeri karakterleri temsil eder. Ayrıca gördüğünüz gibi, “karakter kümesi” denen şey, temelde belli karakterlerle belli sayıları eşleştiren bir tablodan ibarettir…

Mesela ascii tablosunda “10” sayısının “yeni satır” karakterini temsil ettiğini görüyoruz (O tabloda “dec” sütununa bakın). ascii tablosu bugün için de geçerlidir. Bu yüzden bu tablodaki karakterleri modern sistemler de kabul edecektir. Mesela Python’da, chr() fonksiyonundan da yararlanarak şöyle bir şey yazabiliriz:
>>> print “Merhaba” + chr(10) + “dünya”

Merhaba
dünya

Gördüğünüz gibi, gerçekten de “10” sayısı yeni bir satıra geçmemizi sağladı. Burada chr() fonksiyonu ascii tablosundaki sayıların karakter karşılıklarını görmemizi ve kullanabilmemizi sağlıyor…

Aynı tabloda “9” sayısının ise “sekme” karakterini temsil ettiğini görüyoruz. Bu da bize Python’da şöyle bir şey yazma olanağı sağlıyor:
>>> print “Merhaba” + chr(9) + “dünya”

Merhaba dünya

Yukarıda yazdığımız kodları işleten Python, “Merhaba” ve “dünya” kelimeleri arasında bir sekmelik boşluk bıraktı… Eğer buradaki sekme boşluğunun az olduğunu düşünüyorsanız kodunuzu şöyle de yazabilirsiniz:
>>> print “Merhaba” + chr(9) * 2 + “dünya”

Merhaba dünya

chr(9)‘a karşılık gelen sekme karakterini istediğiniz kadar tekrar ederek, karakter dizileri arasında istediğiniz boyutta sekmeler oluşturabilirsiniz… Elbette bunu Python’da “\t” kaçış dizisini kullanarak da yapabileceğinizi biliyorsunuz.

Eğer ascii sisteminden yararlanıp bilgisayarınızın bir “bip” sesi çıkarmasını isterseniz sadece şöyle bir şey yazmanız yeterli olacaktır:
>>> print chr(7)

!bip!

Ancak bu biplemeyi (eğer kernel modüllerinden biri olan “pcspkr” yüklü değilse) GNU/Linux sistemlerinde duyamayabilirsiniz…

Elbette ascii tablosu sadece yukarıdaki görünmez karakterlerden ibaret değildir. Tablodan gördüğümüz gibi, 33’ten 128’e kadar olan kısımda ekrana basılabilen karakterler yer alıyor. Mesela “a” harfi “97” sayısı ile gösteriliyor. Dolayısıyla Python’da şöyle bir şey yazabiliyoruz:
>>> print “Merhab” + chr(97) + dünya”

Merhabadünya

Burada iki kelime arasında tabii ki boşluk yer almıyor. Boşluk karakterini kendiniz yerleştirebilirsiniz… Ama eğer ascii kodlarını doğrudan karakter dizilerinin içinde kullanmak isterseniz, ascii tablosunda “dec” sütunu yerine “oct” sütunundaki sayıları da kullanabilirsiniz. Tablodaki “oct” sütununu kontrol ettiğimizde “a” harfinin “141” sayısına karşılık geldiğini görüyoruz. O halde şöyle bir kod yazmamız mümkün:
>>> print “Merhab\141 dünya”

Merhaba dünya

Burada “141” sayısını doğrudan kullanmadığımıza dikkat edin. Python’un ekrana “141” yazdırmak istediğimizi zannetmemesi için “\” kaçış dizisini kullanarak, Python’a “o 141 bildiğin 141 değil,” gibi bir mesaj vermiş oluyoruz…

“Yok, ben illa dec sütunundaki ondalık sayıları kullanmak istiyorum,” diyorsanız sizi kıracak değiliz. Bunu elbette şu şekilde yapabileceğinizi biliyorsunuz:
>>> print “Merhab%s dünya” %chr(97)

Dikkat ederseniz, ascii tablosunda “Hx” (Hexadecimal) adlı bir sütun daha var. Eğer bu sütundaki sayılar size daha sevimli geliyorsa şöyle bir yazım tarzı benimseyebilirsiniz:
>>> print “Merhab\x61 dünya”

ascii tablosunu incelediğinizde, bu tabloda bazı şeylerin eksik olduğu gözünüze çarpmış olmalı. Mesela bu tabloda “çşöğüı” gibi harfleri göremiyoruz…

Şimdi Python’da şöyle bir kod yazdığımızı düşünelim:
print “Türkçe karakterler: şçöğüıİ”

Eğer bu kodları doğrudan etkileşimli kabuk üzerinde çalıştırmışsanız Python size düzgün bir çıktı vermiş olabilir. Ancak bu sizi yanıltmasın. Etkileşimli kabuk pratik bir araçtır, ama her zaman güvenilir bir araç olduğu söylenemez. Burada aldığınız çıktıların her ortamda aynı çıktıyı vereceğinden emin olamazsınız. O yüzden asıl programlarınızda doğrudan yukarıdaki gibi bir kod yazamazsınız.

Bu kodu bir metin dosyasına yazıp kaydettikten sonra programı çalıştırmak istediğimizde şöyle bir çıktı alırız:
SyntaxError: Non-ascii character ‘\xfc’ in file deneme.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

Burada gördüğünüz gibi, Python “ascii olmayan” karakterler kullandığımızdan yakınıyor… Aslında bu çok doğal. Çünkü dediğimiz ve gördüğümüz gibi, “şçöğüıİ” harfleri ascii tablosunda yer almıyor…

Bu yazının “Giriş” bölümündeki kaba tarifte de ifade ettiğimiz gibi, “ascii” Türkçe karakterleri tanımayan bir karakter kodlama biçimidir. Aslında ascii sadece Türkçe’yi değil, İngilizce dışındaki hiç bir dilin özel karakterlerini tanımaz.

Python varsayılan olarak ascii kodlamasını kullanır… Hemen bunu teyit edelim:
>>> import sys
>>> sys.getdefaultencoding()

‘ascii’

Demek ki Python’daki varsayılan kodlama biçimi hakikaten “ascii” imiş… Yukarıdaki durum nedeniyle, Python “ascii” tablosunda yer almayan bir karakterle karşılaştığı zaman doğal olarak hata mesajında gördüğümüz çıktıyı veriyor.

Bu arada, ascii’nin 7-bitlik bir sistem olduğunu söylemiştik. Peki “7-bitlik” ne demek? Hemen kısaca onu da açıklayalım:

Bildiğiniz gibi bilgisayarların temelinde 1’ler ve 0’lar yatar. Bilgisayarlar yalnızca bu sayıları anlayıp bu sayılarla işlem yapabilir. Bu 1 ve 0’ların her birine “bit” adı verilir. Bu 1 ve 0’ların 7 tanesi yan yana gelince 7-bitlik bir sayı oluşturur! Gayet mantıklı, değil mi?

İşte ascii sisteminde tanımlanan bütün karakterler 7-bitlik bir sayı içine sığdırılabiliyor. Yani 7 adet 1 ve 0 bütün ascii karakterleri temsil etmeye yetiyor. Mesela “F” harfinin ascii karşılığı olan “70” sayısı ondalık bir sayıdır. Bu ondalık sayı ikili düzende 1000110 sayısına karşılık gelir. Python’da herhangi bir ondalık sayının ikili düzende hangi sayıya karşılık geldiğini bulmak için bin() adlı fonksiyondan yararlanabilirsiniz:
>>> bin(70)
‘0b1000110’

Bu sayının başındaki “0b” karakterleri Python’un ikili sayıları göstermek için kullandığı bir araçtır. Bu araç Python’a bir şeyler ifade ediyor olabilir, ama bize bir şey ifade etmez. O yüzden bu sayıda bizi ilgilendiren kısım “1000110”.

Gördüğünüz gibi burada toplam 7 adet 1 ve 0 var… Başka bir örnek verelim: ascii tablosunda “r” harfi “114” sayısına karşılık geliyor. Bu ondalık sayının ikili düzendeki karşılığı 1110010 sayısıdır:
>>> bin(114)
‘0b1110010′

Yine gördüğünüz gibi, bu ikili sayı da 7 adet 1 ve 0’dan oluşuyor. Dolayısıyla bu da 7-bitlik bir sayıdır. 7-bitle gösterilebilecek son sayı 127’dir. Bunun da ikili düzendeki karşılığı 1111111 sayısıdır. 128 sayısı ikili düzende 10000000 olarak gösterilir. Gördüğünüz gibi 128’in ikili düzendeki karşılığı olan sayı 7-bit değil. Çünkü burada 7 adet 1 ve 0 yerine 8 adet 1 ve 0 var… Dolayısıyla 7 bit kullanarak 0 sayısı ile birlikte 128 adet ondalık sayıyı gösterebiliyoruz. 129. sayı ancak 8 bit kullanılarak gösterilebiliyor.

1990’lı yılların ortalarına kadar bilgisayar sistemleri sadece bu 7-bitlik veriler ile işlem yapıyordu. Ancak 90’lu yılların ortalarından itibaren bütün bilgisayar sistemleri 8 bitlik verileri de depolayabilmeye başladı. 8. bitin gelişiyle birlikte, 7-bitlik sistemin sunduğu 128 karaktere ek olarak bir 128 karakteri daha temsil edebilme olanağı doğdu. Çünkü 8-bitlik sistemler 28 = 256 adet karakterin kodlanmasına imkan tanır.

128 karakteri destekleyen standart ascii’nin İngilizce dışındaki karakterleri gösterememesi ve 8. bitin sağladığı olanaklar göz önünde bulundurularak ortaya “Genişletilmiş ascii” diye bir şey çıktı. Ancak ilk 128 karakterden sonra gelen 128 karakterin hangi karakterleri temsil edeceği konusu, yani “Genişletilmiş ascii” denen sistem standart bir yapıya hiç bir zaman kavuşamadı. Bilgisayar üreticileri bu 8. biti kendi ihtiyaçlarına göre doldurma yolunu seçtiler. Böylece ortaya “kod sayfası” (codepage) denen bir kavram çıktı.

Özellikle IBM ve Microsoft gibi büyük şirketlerin, kendi ihtiyaçlarına ve farklı ülkelere göre düzenlenmiş farklı farklı kod sayfaları bulunur. Örneğin Microsoft firmasının Türkiye’ye gönderdiği bilgisayarlarda kullandığı, 857 numaralı bir kod sayfası vardır. Bu kod sayfasına http://msdn.microsoft.com/en-us/library/cc195068.aspx adresinden ulaşabilirsiniz. Bu adresteki kod sayfasında göreceğiniz gibi, sayılar 32’den başlıyor. ascii tablosunun ilk 32 sayısı ekranda görünmeyen karakterleri temsil ettiği için Microsoft bunları gösterme gereği duymamış. Bu tabloda 128’e kadar olan kısım zaten standart ascii’dir ve bütün kod sayfalarında ilk 128’lik kısım aynıdır. Sonraki 128’lik kısım ise farklı kod sayfalarında farklı karakterlere karşılık gelir… Örneğin buradaki 857 numaralı kod sayfasında ikinci 128’lik kısım özel karakterlere ayrılmıştır. Bu kod sayfası Türkçe’deki karakterleri düzgün gösterebilmek için üretildiğinden bu listede “ş”, “ç”, “ö”, “ğ”, “ı” ve “İ” gibi harfleri görebiliyoruz. Ama eğer http://msdn.microsoft.com/en-us/library/cc195065.aspx adresindeki 851 numaralı kod sayfasına bakacak olursanız, bu listede ikinci 128’lik kısmın 857 numaralı kod sayfasındakilerden farklı karakterlere ayrıldığını görürsünüz. Çünkü 851 numaralı kod sayfası Yunan alfabesindeki harfleri gösterebilmek için tasarlanmıştır…

Kod sayfaları dışında, az çok standartlaşmış karakter kümeleri de bu dönemde İngilizce dışındaki dillerin karakter ihtiyaçlarını karşılamak için kullanılıyordu. Örneğin “ISO” karakter kümeleri de kod sayfalarına benzer bir biçimde 8. biti olabildiğince standartlaştırmaya çalışan girişimlerdi. ISO-8859 karakter kümeleri bunların en bilinenlerindendir. Bunlar içinde Türkçe’ye ayrılan küme ISO-8859-9 adlı karakter kümesidir. ISO-8859-9 karakter kümesine http://czyborra.com/charsets/iso8859.html#ISO-8859-9 adresinden ulaşabilirsiniz…

Hatırlarsanız yukarıda chr() adlı bir fonksiyondan bahsetmiştik. Bu fonksiyon kendisine argüman olarak verilen ondalık bir sayının ascii tablosundaki karşılığını gösteriyordu. Python’da bir de bu chr() fonksiyonunun yaptığı işin tam tersini yapan başka bir fonksiyon daha bulunur. Bu fonksiyonun adı ord()‘dur. ord() fonksiyonunu şöyle kullanıyoruz:
>>> ord(“g”)

103

Demek ki “g” karakterinin ascii tablosundaki karşılığı 103’müş…

Bu chr() ve ord() fonksiyonları farklı platformlarda farklı davranabilir. Örneğin:
>>> print ord(“ç”)

135

>>> print chr(135)

ç

Gördüğünüz gibi, ord(“ç”) çıktısı 135 sonucunu veriyor. 135 sayısına karşılık gelen karakter standart ascii’nin dışında kalır. Çünkü dediğimiz gibi standart ascii sadece 128 karakterden oluşur… Dolayısıyla “ç” karakteri ikinci 128’lik kısımda yer alır. Ancak dediğimiz gibi, yukarıdaki sonuç epey yanıltıcıdır. Çünkü bu çıktıyı yalnızca Windows’ta elde edebilirsiniz. Aynı komut GNU/Linux üzerinde hata verecektir. Microsoft firması ikinci 128’lik kısım için kendine özgü bir kod sayfası kullanıyor ve 135 sayısı bu özel kod sayfasında “ç” karakterine karşılık geliyor. İsterseniz bir de öteki Türkçe karakterlerin durumunu kontrol edelim:
>>> for i in “şçöğüıİ”:
… print i, ord(i)

ş 159
ç 135
ö 148
ğ 167
ü 129
ı 141
İ 152

Gördüğünüz gibi bütün Türkçe karakterler 128’den büyük. O yüzden bunlar standart ascii tablosuna girmiyor. Ama Microsoft’un kullandığı 857 numaralı kod sayfası sayesinde bu karakterler ikinci 128’lik kısma girebilmiş… Ancak dediğim gibi, yukarıdaki çıktı güvenilir değildir. Bu komutu ben Windows kurulu bir bilgisayarda verdim. Aynı komutu GNU/Linux işletim sisteminde verdiğinizde hiç beklemediğiniz sonuçlar elde edersiniz. Çünkü elbette GNU/Linux işletim sistemleri Microsoft’un 857 numaralı kod sayfasını kullanmıyor… GNU/Linux farklı bir kodlama sistemini kullanır. Bunun ne olduğunu biraz sonra göreceğiz. Şimdilik biz konumuza devam edelim.

Buraya kadar anlattıklarımızdan anlaşılacağı gibi, standart ascii tablosu İngilizce dışındaki dillere özgü karakter ve simgeleri göstermek konusunda yetersizdir. Standart ascii 128 karakterden ibarettir. Genişletilmiş ascii ise toplam 256 karakterden oluşur. Ancak ilk 128 karakterden sonra gelen ikinci 128’lik kısım standart bir yapıya sahip değildir. Her üretici bu ikinci 128’lik kısmı kendi “kod sayfası”ndaki karakterlerle doldurur. Bu yüzden genişletilmiş ascii’ye güvenip herhangi bir iş yapamazsınız.

İşte tam da bu noktada “unicode” denen şey devreye girer. O halde gelelim bu “unicode” mevzuuna…
12.3. unicode

Her ne kadar ascii kodlama sistemi İngilizce dışındaki karakterleri temsil etmek konusunda yetersiz kalsa da insanlar uzun süre ascii’yi temel alarak çalıştılar. Yerel ihtiyaçları gidermek için ise 8. bitin sağladığı 128 karakterlik alandan ve üreticilerin kendi kod sayfalarından yararlanıldı. Ancak bu yaklaşımın yetersizliği gün gibi ortadadır. Bir defa 7 bit bir kenara, 8 bit dahi dünya üzerindeki bütün dillerin karakter ve simgelerini göstermeye yetmez. Örneğin Asya dillerinin alfabelerindeki harf sayısını temsil etmek için 256 karakterlik alan kesinlikle yetmeyecektir ve yetmemiştir de… Ayrıca mesela tek bir metin içinde hem Türkçe hem de Yunanca karakterler kullanmak isterseniz ascii sizi yarı yolda bırakacaktır. Türkçe için 857 numaralı kod sayfasını (veya iso-8859-9 karakter kümesini) kullanabilirsiniz. Ama bu kod sayfasında Yunanca harfler yer almaz… Onun için 851 numaralı kod sayfasını veya iso-8859-7 karakter kümesini kullanmanız gerekir. Ancak bu iki kod sayfasını aynı metin içinde kullanmanız mümkün değil…

İşte bütün bu yetersizlikler “evrensel bir karakter kümesi” oluşturmanın gerekliliğini ortaya çıkardı. 1987 yılında Xerox firmasından Joseph D. Becker ve Lee Collins ile Apple firmasından Mark Davis böyle bir “evrensel karakter kümesi” oluşturabilmenin altyapısı üzerinde çalışmaya başladı. “unicode” kelimesini ortaya atan kişi Joe Becker’dir. Becker bu kelimeyi “benzersiz (unique), birleşik (unified) ve evrensel (universal) bir kodlama biçimi” anlamında kullanmıştır.

Joseph Becker’in 29 Ağustos 1988 tarihinde yazdığı Unicode 88 başlıklı makale, unicode hakkındaki ilk taslak metin olması bakımından önem taşır. Becker bu makalede neden unicode gibi bir sisteme ihtiyaç duyulduğunu, ascii’nin İngilizce dışındaki dillere ait karakterleri göstermekteki yetersizliğini ve herkesin ihtiyacına cevap verebilecek bir sistemin nasıl ortaya çıkarılabileceğini anlatır. Bu makaleye http://unicode.org/history/unicode88.pdf adresinden ulaşabilirsiniz.

1987 yılından itibaren unicode üzerine yapılan yoğun çalışmaların ardından 1991 yılında hem “Unicode Konsorsiyum” kurulmuş hem de ilk unicode standardı yayımlanmıştır. Unicode ve bunun tarihi konusunda en ayrıntılı bilgiyi http://www.unicode.org/ adresinden edinebilirsiniz…

İlk unicode standardı 16-bit temel alınarak hazırlanmıştır. Unicode kavramı ilk ortaya çıktığında Joe Becker 16 bit’in dünyadaki bütün dillere ait karakterleri temsil etmeye yeteceğini düşünüyordu. Ne de olsa;

27 = 128

28 = 256

216 = 65536

Ancak zamanla 16 bit’in dahi tüm dilleri kapsayamayacağı anlaşıldı. Bunun üzerine unicode 2.0’dan itibaren 16-bit sınırlaması kaldırılarak, dünya üzerinde konuşulan dillere ilaveten arkaik dillerdeki karakterler de temsil edilebilme olanağına kavuştu. Dolayısıyla “unicode 16-bitlik bir sistemdir,” yargısı doğru değildir. Unicode ilk çıktığında 16-bitlikti, ama artık böyle bir sınırlama yok…

Unicode, ascii’ye göre farklı bir bakış açısına sahiptir. ascii’de sistem oldukça basittir. Buna göre her sayı bir karaktere karşılık gelir. Ancak unicode için aynı şeyi söylemek mümkün değil. Unicode sisteminde karakterler yerine “kod konumları” (code points) bulunur. O yüzden unicode sisteminde “baytlar” üzerinden düşünmek yanıltıcı olacaktır…

Örneğin http://www.unicode.org/charts/PDF/U0100.pdf adresindeki “Latin Extended A” adlı unicode tablosuna bakalım. Bu tablo Türkçe ve Azerice’nin de dahil olduğu bazı dillere özgü karakterleri barındırır. Bu sayfada yer alan tabloda her karakterin bir kod konumu bulunduğunu görüyoruz. Mesela “ğ” harfinin kod konumu 011F’dir. Unicode dilinde kod konumları geleneksel olarak “U+xxxx” şeklinde gösterilir. Mesela “ğ” harfinin kod konumu “U+011F”dir. Esasında bu “011F” bir onaltılık sayıdır. Bunun ondalık sayı olarak karşılığını bulmak için int() fonksiyonundan yararlanabilirsiniz:
>>> int(“011F”, 16)

287

Python’da chr() fonksiyonuna çok benzeyen unichr() adlı başka bir fonksiyon daha bulunur. chr() fonksiyonu bir sayının ascii tablosunda hangi karaktere karşılık geldiğini gösteriyordu. unichr() fonksiyonu ise bir sayının unicode tablosunda hangi kod konumuna karşılık geldiğini gösterir. Mesela yukarıda gördüğümüz “287” sayısının hangi kod konumuna karşılık geldiğine bakalım:
>>> unichr(287)

u’\u011f’

Gördüğünüz gibi “ğ” harfinin kod konumu olan “011F”yi elde ettik. Burada Python kendi iç işleyişi açısından “011F”yi “u’\u011F” şeklinde gösteriyor. Yukarıdaki kodu şöyle yazarak doğrudan “ğ” harfini elde edebilirsiniz:
>>> print unichr(287)

‘ğ’

Peki doğrudan bir sayı vererek değil de, karakter vererek o karakterin unicode kod konumunu bulmak mümkün mü? Elbette. Bunun için yine ord() fonksiyonundan yararlanabiliriz:
>>> ord(u”ğ”)

287

ord() fonksiyonu bir karakterin kod konumunu ondalık sayı olarak verecektir. Elde ettiğiniz bu ondalık sayıyı unichr() fonksiyonuna vererek onaltılık halini ve dolayısıyla unicode kod konumunu elde edebilirsiniz:
>>> unichr(287)

u’\u011f’

Bu arada ord() fonksiyonunu burada nasıl kullandığımıza dikkat edin. Sadece ord(“ğ”) yazmak Python’un hata vermesine sebep olacaktır. Çünkü özünde ord() fonksiyonu sadece 0-256 aralığındaki ascii karakterlerle çalışır. Eğer yukarıdaki kodu ord(“ğ”) şeklinde yazarsanız, şöyle bir hata alırsınız:
>>> ord(“ğ”)

ValueError: chr() arg not in range(256)

“ğ”nin değeri “287” olduğu ve bu sayı da 256’dan büyük olduğu için ord() fonksiyonu normal olarak bu karakteri gösteremeyecektir. Ama eğer siz bu kodu ord(u”ğ”) şeklinde başına bir “u” harfi getirerek yaparsanız mutlu mesut yaşamaya devam edebilirsiniz… Biraz sonra bu “u” harfinin tam olarak ne işe yaradığını göreceğiz. Şimdilik biz yine yolumuza kaldığımız yerden devam edelim.

İsterseniz elimiz alışsın diye “ğ” dışındaki bir Türkçe karakteri de inceleyelim. Mesela “ı” harfini alalım. Bu da yalnızca Türk alfabesinde bulunan bir harftir…
>>> ord(u”ı”)

305

Demek ki “ı” harfinin unicode kod konumu 305 imiş… Ancak bildiğiniz gibi bu ondalık bir değerdir. Unicode kod konumları ise onaltılık sisteme göre gösterilir. O halde kodumuzu yazalım:
>>> unichr(305)

u’\u0131′

Burada Python’un kendi eklediği “u’\u” kısmını atarsak “0131” sayısını elde ederiz. Test etmek amacıyla bu “0131” sayısının ondalık karşılığını kontrol edebileceğinizi biliyorsunuz:
>>> int(“0131″, 16)

305

Şimdi eğer http://www.unicode.org/charts/PDF/U0100.pdf adresindeki unicode tablosuna bakacak olursanız “ı” harfinin kod konumunun gerçekten de “0131” olduğunu göreceksiniz. İsterseniz bakın…

Doğrudan “ı” harfini elde etmek isterseniz şöyle bir şey de yazabilirsiniz:
>>> print u’\u0131′

ı

Unicode sistemi bu kod konumlarından oluşan devasa bir tablodur. Unicode tablosuna http://www.unicode.org/charts adresinden ulaşabilirsiniz. Ancak unicode sadece bu kod konumlarından ibaret bir sistem değildir. Zaten unicode sistemi sadece bu kod konumlarından ibaret olsaydı pek bir işe yaramazdı. Çünkü unicode sistemindeki kod konumlarının bilgisayarlarda doğrudan depolanması mümkün değildir. Bilgisayarların bu kod konumlarını işleyebilmesi için bunların bayt olarak temsil edilebilmesi gerekir. İşte unicode denen sistem bir de bu kod konumlarını bilgisayarların işleyebilmesi için bayta çeviren “kod çözücülere” sahiptir.

Unicode sistemi içinde UTF-8, UTF-16 ve UTF-32 gibi kod çözücüler vardır. Bunlar arasında en yaygın kullanılanı UTF-8’dir ve bu kodlama sistemi GNU/Linux sistemlerinde de standart olarak kabul edilir. Python programlama dili de 3.x sürümlerinden itibaren varsayılan kodlama biçimi olarak UTF-8’i kullanır. Hemen bunu teyit edelim.

Python 3.x sürümünde şöyle bir komut verelim:
>>> import sys
>>> sys.getdefaultencoding()

‘utf-8’

Yukarıda da gösterdiğimiz gibi, Python’un 2.x sürümlerinde bu komutun çıktısı ‘ascii’ idi… Kod çözücüler her kod konumunu alıp farklı bir biçimde kodlarlar. Ufak bir örnek yapalım:
>>> unicode.encode(u”ğ”, “utf-8″)

‘\xc4\x9f’

>>> unicode.encode(u”ğ”, “utf-16″)

‘\xff\xfe\x1f\x01’

>>> unicode.encode(u”ğ”, “utf-32”)

‘\xff\xfe\x00\x00\x1f\x01\x00\x00’

Buradaki unicode.encode() yapısına kafanızı takmayın. Biraz sonra bunları iyice inceleyeceğiz. Burada benim amacım sadece farklı kod çözücülerin karakterleri nasıl kodladığını göstermek… Dediğim gibi, bu kod çözücüler içinde en gözde olanı utf-8’dir ve bu çözücü GNU/Linux’ta da standarttır.
12.4. Python’da unicode Desteği

ascii ve unicode’nin ne olduğunu öğrendik. Şimdi sıra geldi Python’daki unicode desteği konusunu işlemeye…

Esasında unicode konusundan bahsederken bunun Python’a yansımasının bir kısmını da görmedik değil. Örneğin unichr() fonksiyonunu kullanarak bir kod konumunun hangi karaktere karşılık geldiğini bulabileceğimizi öğrendik:
>>> print unichr(351)

ş

Ancak daha önce söylediğimiz şeyler parça parça bilgiler içeriyordu. Bu bölümde ise “gerçek hayatta” unicode ve Python’u nasıl bağdaştıracağımızı anlamaya çalışacağız.

Python’da karakterlere ilişkin iki farklı tip bulunur: “karakter dizileri” (strings) ve “unicode dizileri” (unicode strings). Mesela şu bir karakter dizisidir:
>>> “elma”

Hemen kontrol edelim:
>>> type(“elma”)

Şu ise bir unicode dizisidir:
>>> u”elma”

Bunu da kontrol edelim:
>>> type(u”elma”)

Gördüğünüz gibi, unicode dizileri, karakter dizilerinin başına bir “u” harfi getirilerek kolayca elde edilebiliyor.

Peki bir karakter dizisini “unicode” olarak tanımlamanın bize ne faydası var? Bir örnek bin söze bedeldir!.. O yüzden isterseniz derdimizi bir örnekle anlatmaya çalışalım. Şuna bir bakın:
>>> kardiz = “ışık”
>>> len(kardiz)

7

Gördüğünüz gibi, “ışık” kelimesinde sadece dört karakter bulunduğu halde len() fonksiyonu “7” sonucunu veriyor… Bu bölümün en başında bahsettiğimiz makalede de söylediğimiz gibi len() fonksiyonu aslında bir karakter dizisinde kaç karakter olduğuna bakmaz. Bu fonksiyonun ilgilendiği şey o karakter dizisinin içerdiği bayt sayısıdır. “ışık” kelimesini etkileşimli kabukta yazacak olursanız sorunun nerede olduğunu görebilirsiniz:
>>> “ışık”

‘\xc4\xb1\xc5\x9f\xc4\xb1k’

Burada “xc4”, “xb1”, “xc5”, “x9f”, “xc4”, “xb1” ve “k” şeklinde gösterilen toplam 7 baytlık bir veri var. Dolayısıyla burada len() fonksiyonunun “4” çıktısı vermesini boşuna beklememek lazım. Bir de şuna bakın:
>>> unidiz = u”ışık”
>>> len(unidiz)

4

Gördüğünüz gibi, “ışık” karakter dizisini unicode olarak tanımladığımızda Python bu dizideki gerçek karakter sayısını verecektir. İsterseniz biraz önce yaptığımız gibi u”ışık” adlı unicode dizisini etkileşimli kabukta yazarak durumu daha net görmeyi tercih edebilirsiniz:
>>> u”ışık”

u’\u0131\u015f\u0131k’

Bu çıktıda görünen “unicode kod konumları”na özellikle dikkat edin. Python bu kod konumlarını birer baytmış gibi görecektir. Eğer unicode tablosunu açıp bakarsanız, bu kod konumlarının hangi harflere karşılık geldiğini görebilirsiniz. Veya daha önce söylediğimiz gibi, şu yolu da kullanabilirsiniz:
>>> ord(u”\u0131″)

305

>>> unichr(305)

u’\u0131′

>>> print unichr(305)
ı

Ya da bu üç aşamayı tek adımda halletmek de isteyebilirsiniz:
>>> print unichr(ord(u”\u0131″))

ı

Demek ki karakter dizilerini “unicode” olarak tanımlamak programlarımızın çalışması açısından hayati önem taşıyabiliyormuş… Ama tabii bu daha işin ufak bir boyutu. Bir de şuna bakın:
>>> kardiz = “ışık”
>>> print kardiz.upper()

ışıK

Gayet başarısız bir sonuç! Karakter dizilerinin metotlarından biri olan upper() metodu sadece “k” harfini büyütebildi… Geri kalan harfleri ise olduğu gibi bıraktı. Ama artık siz bu sorunun üstesinden nasıl gelebileceğimizi az çok tahmin ediyorsunuzdur:
>>> unidiz = u”ışık”
>>> print unidiz.upper()

IŞIK
12.4.1. Python Betiklerinde unicode Desteği

Bu bölümün başında ascii konusundan bahsederken, şöyle bir örnek vermiştik:
print “Türkçe karakterler: şçöğüıI”

Dedik ki, eğer bu satırı bir metin dosyasına yazıp kaydeder ve ardından bu programı çalıştırırsanız şöyle bir hata mesajı alırsınız:
SyntaxError: Non-ascii character ‘\xfc’ in file deneme.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

Esasında biz bu hatanın üstesinden nasıl gelebileceğimizi daha önceki derslerimizde edindiğimiz bilgiler sayesinde çok iyi biliyoruz. Python derslerinin ta en başından beri yazdığımız bir satır, bizim yukarıdaki gibi bir hata almamızı engelleyecektir:
#-*-coding: utf-8-*-

Hatırlarsanız, unicode konusundan söz ederken unicode sistemi içinde bazı kod çözücülerin yer aldığını söylemiştik. Orada da dediğimiz gibi, “utf-8” de bu kod çözücülerden biri ve en gözde olanıdır. Yukarıdaki satır yardımıyla, yazdığımız programın “utf-8” ile kodlanmasını sağlıyoruz. Böylelikle programımız içinde geçen ascii dışı karakterler çıktıda düzgün gösterilebilecektir. GNU/Linux sistemlerinde “utf-8” kodlaması her zaman işe yarayacaktır. Ancak Windows’ta utf-8 yerine “cp1254” adlı özel bir kod çözücü kullanmanız gerekebilir. Dolayısıyla eğer Windows kullanıyorsanız yukarıdaki satırı şöyle yazmanız gerekebilir:
#-*-coding: cp1254-*-

Yazacağınız betiklerin en başına yukarıdaki gibi bir satır koyarak, programlarınıza unicode desteği vermiş oluyorsunuz. Yazdığınız o satır sayesinde Python kendi varsayılan kod çözücüsü olan “ascii”yi kullanarak programınızın çökmesine sebep olmak yerine, sizin belirlediğiniz kod çözücü olan utf-8’i (veya cp-1254’ü) kullanarak programlarınızın içinde rahatlıkla İngilizce dışındaki karakterleri de kullanmanıza müsaade edecektir.

Hatırlarsanız, unicode sistemleri içindeki kod konumlarının bilgisayarlar açısından pek bir şey ifade etmediğini, bunların bilgisayarlarda depolanabilmesi için öncelikle uygun bir kod çözücü yardımı ile bilgisayarın anlayabileceği baytlara dönüştürülmesi gerektiğini söylemiştik. İsterseniz biraz da bunun ne demek olduğunu anlamamıza yardımcı olacak birkaç örnek yapalım.

Biliyoruz ki, Python’da unicode dizileri oluşturmanın en kolay yolu, karakter dizilerinin başına bir adet “u” harfi eklemektir:
>>> uni_diz = u”ışık”

Bu unicode dizisini etkileşimli kabukta yazdırdığımız zaman şöyle bir çıktı elde ediyoruz:
>>> uni_diz

u’\u0131\u015f\u0131k’

Burada gördüğünüz şey bir bayt dizisi değildir. Burada gördüğümüz şey bir dizi unicode kod konumudur… Dolayısıyla bu unicode dizisi bu haliyle bilgisayarda depolanamaz. İsterseniz deneyelim:
>>> f = open(“deneme.txt”, “w”)
>>> f.write(uni_diz)

Bu kodlar şöyle bir hata verecektir:
Traceback (most recent call last):
File “”, line 1, in
UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-2:
ordinal not in range(128)

Python, unicode kod konumlarından oluşmuş bir diziyi bilgisayara kaydetmek istediğimizde olanca iyi niyetiyle bu kod konumlarını bilgisayarın anlayabileceği bir biçime dönüştürmeye çalışır. Bunu yaparken de tabii ki varsayılan kod çözücüsü olan “ascii”yi kullanmayı dener. Eğer “uni_diz” adlı değişkende sadece İngilizce karakterler olsaydı, Python bunları ascii yardımıyla bilgisayarın anlayabileceği bir biçime çevirir ve rahatlıkla dosyaya yazdırabilirdi. Ancak burada bulunan Türkçe karakterler nedeniyle ascii kod çözücüsü bu karakterleri çözemez ve programın çökmesine yol açar… Bu yüzden bizim yapmamız gereken şey, unicode dizilerini depolayabilmek için öncelikle bunları uygun bir kod çözücü yardımıyla bilgisayarın anlayabileceği bir biçime getirmektir. Biraz sonra bunu nasıl yapacağımızı göreceğiz. Ama biz şimdilik yine yolumuza devam edelim.

ascii, unicode ve bunların Python’la ilişkisi konusunda temel bilgileri edindiğimize göre Python’daki unicode desteğinin biraz daha derinlerine inmeye başlayabiliriz. Bunun için isterseniz öncelikle unicode ile ilgili metotlara bir göz atalım.
12.4.2. unicode() Fonksiyonu

Hatırlarsanız Python’da bir unicode dizisi oluşturmak için karakter dizisinin başına bir adet “u” harfi getirmemizin yeterli olacağını söylemiştik. Aynı şeyi “unicode()” adlı bir fonksiyonu kullanarak da yapabiliriz:
>>> unicode(“elma”)
>>> type(unicode(“elma”))

Burada dikkat etmemiz gereken önemli bir nokta var. “unicode()” adlı fonksiyon ikinci (ve hatta üçüncü) bir parametre daha alır. Önce ikinci parametrenin ne olduğuna bakalım:
>>> unicode(“elma”, “utf-8”)

Burada “elma” adlı karakter dizisini “utf-8” adlı kod çözücüyü kullanarak bir unicode dizisi haline getirdik. “ascii”nin kendisi unicode sistemi içinde yer almasa da, “ascii” tablosunda bulunan karakterler unicode sisteminde de aynı şekilde yer aldığı için, burada kullandığımız “unicode()” fonksiyonu bir karakter dizisini “ascii” ile kodlamamıza da müsaade eder:
>>> unicode(“elma”, “ascii”)

Esasında eğer unicode() fonksiyonunun ikinci parametresini belirtmezseniz Python otomatik olarak sizin “ascii”yi kullanmak istediğinizi varsayacaktır:
>>> unicode(“elma”)

Peki karakter dizilerini bu şekilde kodlamak ne işimize yarar? Bunu anlamak için şöyle bir örnek verelim:
>>> a = “şırınga”
>>> print a.upper()

şıRıNGA

Gördüğünüz gibi, karakter dizilerinin metotlarından biri olan upper(), içindeki Türkçe karakterlerden ötürü “şırınga” kelimesini büyütemedi. Bu kelimeyi düzgün bir şekilde büyütebilmek için iki yöntem kullanabilirsiniz. Önce basit olanını görelim:
>>> a = u”şırınga”
>>> print a.upper()

ŞIRINGA

Burada daha en baştan “şırınga” karakter dizisini unicode olarak tanımladık. Bu işlemi, karakter dizisinin başına sadece bir “u” harfi getirerek yaptık. Peki ya baştaki karakter dizisini değiştirme imkanımız yoksa ne olacak? İşte bu durumda ikinci yolu tercih edebiliriz:
>>> a = “şırınga”
>>> b = unicode(a, “utf-8”)
>>> print b.upper()

ŞIRINGA

unicode() fonksiyonu karakterleri daha esnek bir biçimde kodlamamızı sağlar. Eğer burada unicode() fonksiyonunu ikinci parametre olmadan çağırırsanız hata mesajı alırsınız:
>>> b = unicode(a)

UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xc5 in position 0:
ordinal not in range(128)

Daha önce de dediğimiz gibi, ikinci parametrenin belirtilmemesi durumunda Python “ascii” kod çözücüsünü kullanacaktır. O yüzden, “ş” ve “ı” harflerini düzgün görüntüleyebilmek için bizim “utf-8” adlı kod çözücüsünü kullanmamız gerekiyor…

unicode() adlı fonksiyon üçüncü bir parametre daha alır. Bu parametre, kullanılan kod çözücünün, bazı karakterleri düzgün kodlayamaması durumunda Python’un ne yapması gerektiğini belirler. Bu parametre üç farklı değer alır: “strict”, “ignore” ve “replace”. Hemen bir örnek verelim:
>>> b = unicode(a, “ascii”, errors = “strict”)

UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xc5 in position 0:
ordinal not in range(128)

Gördüğünüz gibi, biraz önce aldığımız hatanın aynısını almamıza sebep oldu bu kod… Çünkü “errors” adlı parametrenin varsayılan değeri “strict”tir. Peki “strict” ne anlama geliyor? Eğer “errors” adlı parametreye değer olarak “strict” verirsek, kullanılan kod çözücünün düzgün kodlayamadığı karakterlerle karşılaşıldığında Python bize bir hata mesajı gösterecektir. Dediğimiz gibi, “errors”un varsayılan değeri “strict”tir. Dolayısıyla eğer “errors” parametresini hiç kullanmazsanız, ters durumlarda Python size bir hata mesajı gösterir. Bu parametre “strict” dışında “ignore” ve “replace” adlı iki değer daha alabilir. Önce “ignore”nin ne yaptığına bakalım:
>>> b = unicode(a, “ascii”, errors = “ignore”)
>>> print b.upper()

RNGA

Burada “ignore” değeri, Python’un herhangi bir ters durumda, çözülemeyen karakteri es geçmesini sağlıyor. Bu sebeple Python çözülemeyen karakterleri tamamen ortadan kaldırıyor… Peki “replace” değeri ne işe yarıyor? Hemen bakalım:
>>> b = unicode(a, “ascii”, errors = “replace”)
>>> print b.upper()

????R??NGA

Burada da Python çözülemeyen karakterlerin yerine soru işaretleri yerleştirdi… Eğer Python’un her karakter yerine neden iki soru işareti koyduğunu merak ediyorsanız, bu bölümün en başında bağlantısını verdiğimiz makaleyi inceleyebilirsiniz (ipucu: len() fonksiyonunu kullanarak “şırınga” kelimesindeki Türkçe karakterlerin uzunluğuna bakın…)

Bu anlattığımız konu ile ilgili olarak şöyle basit bir örnek verebiliriz:
#-*-coding:utf-8-*-

a = raw_input(“herhangi bir karakter yazınız: “)
print a.upper()

Eğer kodlarımızı bu şekilde yazarsak istediğimiz sonucu elde edemeyiz. Python ekranda girdiğimiz Türkçe karakterleri bu şekilde düzgün büyütemeyecektir. Yukarıdaki kodların çalışması için şöyle bir şey yazmalıyız:
#-*-coding:utf-8-*-

a = raw_input(“herhangi bir karakter yazınız: “)
print unicode(a, “utf-8”, errors = “replace”).upper()

Böylece unicode’ye duyarlı bir program yazmış olduk. Artık kullanıcılarımız İngiliz alfabesindeki harflerin dışında bir harf girdiklerinde de programımız düzgün çalışacaktır. Kullanıcının, tanınmayan bir karakter girmesi ihtimaline karşılık da “errors” parametresine “replace” değerini verdik…

Yukarıdaki örneğe benzer şekilde, eğer kullanıcılarınızın girdiği karakterlerin sayısına göre işlem yapan bir uygulama yazıyorsanız ya kullanıcılarınızı “ascii” dışında karakter girmemeye zorlayacaksınız, ya da şöyle bir kod yazacaksınız:
#-*-coding:utf-8-*-

a = raw_input(“Bir parola belirleyiniz: “)
print “Parolanız %s karakter içeriyor!”%len(unicode(a, “utf-8″, errors=”replace”))

Eğer burada bir unicode dizisi oluşturmazsanız ölçmeye çalıştığınız karakter uzunluğu beklediğiniz gibi çıkmayacaktır.

Şimdi tekrar unicode kod konumlarını dosyaya kaydetme meselesine dönelim. Bu kısımda öğrendiğimiz unicode() fonksiyonu da kod konumlarını dosyaya kaydetmemizi sağlamaya yetmeyecektir:
>>> kardiz = “ışık”
>>> unikod = unicode(kardiz, “utf-8”)
>>> f = open(“deneme.txt”, “w”)
>>> f.write(unikod)

Bu kodlar şu hatayı verir:
Traceback (most recent call last):
File “”, line 1, in
UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-2:
ordinal not in range(128)

Çünkü unicode() fonksiyonu da aslında bir dönüştürme işlemi yapmaz. Bu fonksiyonun yaptığı şey bir karakter dizisini kod konumları şeklinde temsil etmekten ibarettir… Bunu şu şekilde teyit edebilirsiniz:
>>> kardiz = “ışık”
>>> unikod = unicode(kardiz, “utf-8″)
>>> unikod

u’\u0131\u015f\u0131k’

Burada gördüğümüz şey bayt değil unicode kod konumlarıdır… unicode() fonksiyonu içinde kullandığımız utf-8 çözücüsünün görevi ise “ışık” kelimesini Python’un doğru okumasını sağlamaktır…
12.4.3. encode() ve decode() Metotları

Hatırlarsanız, unicode sisteminde her bir karakterin bir kod konumuna sahip olduğunu söylemiştik. Karakterlerin kod konumlarını ya unicode tablolarına bakarak, ya da Python’daki ord() ve unichr() fonksiyonlarını kullanarak bulabileceğinizi biliyorsunuz. Mesela:
>>> unichr(ord(u”ş”))

u’\u015f’

Benzer bir şeyi unicode() metodunu kullanarak daha da kolay bir şekilde yapabilirsiniz:
>>> unicode(u”ş”)

u’\u015f’

Burada unicode() fonksiyonunu tek parametreyle kullandığımıza dikkat edin. Eğer “utf-8” veya başka bir kod çözücü kullanarak ikinci parametreyi de girersek Python burada bize bir hata mesajı gösterecektir.

Tekrar tekrar söylediğimiz gibi, bu kod konumu esasında bilgisayarlar için çok fazla şey ifade etmez. Bunların bir şey ifade edebilmesi için bir kod çözücü vasıtasıyla kodlanması gerekir. Mesela bu kod konumunu “utf-8” ile kodlamayı tercih edebilirsiniz:
>>> kod_konumu = unicode(u”ş”)
>>> utfsekiz = kod_konumu.encode(“utf-8”)

Burada encode() adlı bir metottan yararlandığımıza dikkat edin.

Böylece unicode kod konumunu “utf-8” kod çözücüsü ile kodlamış oldunuz. Eğer özgün kod konumunu tekrar elde etmek isterseniz bu kez decode() adlı başka bir metottan yararlanabilirsiniz:
>>> utfsekiz.decode(“utf-8”)

u’\u015f’

İşte Python’da asıl dönüştürme işlemlerini yapanlar bu encode() ve decode() adlı metotlardır. Dolayısıyla artık şöyle bir şey yazabilirsiniz:
>>> kardiz = “ışık”
>>> unikod = unicode(kardiz, “utf-8”)
>>> unibayt = unicode.encode(unikod, “utf-8”)
>>> f = open(“deneme.txt”, “w”)
>>> f.write(unibayt)
>>> f.close()

Bu kısmı kısaca özetleyecek olursak şöyle söyleyebiliriz:

Python’da karakterlere ilişkin iki farklı tip bulunur: karakter dizileri ve unicode dizileri

Mesela şu bir karakter dizisidir:
>>> kardiz = “elma”

Bu karakter dizisi 4 baytlık bir veri içerir:
>>> len(kardiz)

4

Şu da bir karakter dizisidir:
>>> kardiz = “ışık”

Bu karakter dizisi ise 7 baytlık bir veri içerir:
>>> len(kardiz)

7

Buradan çıkan sonuca bakarak karakter dizisi ile bayt sayısının aynı şey olmadığını anlamış oluyoruz. Ayrıca len() fonksiyonu da bir karakter dizisindeki karakter sayısını değil bayt sayısını veriyor.

“kardiz” adlı değişkeni etkileşimli kabukta yazdırırsak baytları temsil eden karakterleri tek tek görebiliriz:
>>> kardiz

‘\xc4\xb1\xc5\x9f\xc4\xb1k’

Şu ise bir unicode dizisidir:
>>> unidiz = u”elma”

Gördüğünüz gibi, Python’da unicode dizisi oluşturmak oldukça kolay. Yapmamız gereken tek şey karakter dizisinin başına bir “u” harfi getirmek.

Şu da bir unicode dizisidir:
>>> unidiz = u”ışık”

Bu unicode dizisi, karakter dizilerinin aksine baytlardan değil unicode kod konumlarından oluşur. Eğer yukarıdaki unicode dizisini etkileşimli kabukta yazdıracak olursanız bu unicode kod konumlarını görebilirsiniz:
>>> unidiz

u’\u0131\u015f\u0131k’

Eğer len() fonksiyonunu bu unicode dizisi üzerine uygulayacak olursanız, len() fonksiyonu her bir kod konumunu bir baytmış gibi değerlendirecektir:
>>> len(unidiz)

4

Kod konumlarının bir işe yarayabilmesi için bunların uygun bir kod çözücü yardımıyla bayta çevrilmeleri gerekir. Unicode sistemi içinde UTF-8, UTF-16 ve UTF-32 gibi kod çözücüler vardır. Bu kod çözücülerin her biri, kod konumlarını farklı bir biçimde ve boyutta bayta çevirir. Bu kod çözücüleri içinde en esnek ve yaygın olanı utf-8 adlı kod çözücüdür. Python’da kod konumlarını bayta çevirmek için encode() adlı bir metottan yararlanabiliriz:
>>> unidiz.encode(“utf-8”)

‘\xc4\xb1\xc5\x9f\xc4\xb1k’

Unicode kod konumları bayta çevrildikten sonra artık bir unicode dizisi değil, karakter dizisi olur:
>>> type(unidiz.encode(“utf-8”)

Eğer bir karakter dizisini unicode kod konumları ile temsil etmek isterseniz decode() metodundan yararlanabilirsiniz:
>>> kardiz.decode(“utf-8”)

u’\u0131\u015f\u0131k’

Yukarıdaki işlem şununla aynıdır:
>>> unicode(kardiz, “utf-8″)

u’\u0131\u015f\u0131k’

Böylece Python’daki “unicode” desteğine ilişkin en önemli metotları görmüş olduk. Artık Python’da “unicode”ye ilişkin bazı önemli modülleri de incelemeye geçebiliriz…
12.4.4. unicodedata Modülü

Bu modül unicode veritabanına erişerek, bu veritabanındaki bilgileri kullanmamızı sağlar. Küçük bir örnek verelim:
>>> import unicodedata
>>> unicodedata.name(u”ğ”)

‘LATIN SMALL LETTER G WITH BREVE’

“ğ” harfinin unicode sistemindeki uzun adı “LATIN SMALL LETTER G WITH BREVE”dir. Eğer isterseniz bu ismi ve lookup() metodunu kullanarak söz konusu karakterin unicode kod konumuna da ulaşabilirsiniz:
>>> unicodedata.lookup(“LATIN SMALL LETTER G WITH BREVE”)

u’\u011f’

Bir de şuna bakalım:
>>> unicodedata.category(u”ğ”)

‘L1’

category() metodu ise bir unicode dizisinin unicode sistemindeki kategorisini gösteriyor. Yukarıda verdiğimiz örneğe göre “ğ” harfinin kategorisi “L1” yani “Latin-1”.
12.4.5. codecs Modülü

Bu modül Python’da bir dosyayı, kod çözücüyü de belirterek açmamızı sağlar:
import codecs
f = codecs.open(“unicode.txt”, “r”, encoding=”utf-8″)
for i in f:
print i

Böylece dosya içindeki ascii dışı karakterleri doğru görüntüleyebiliriz…

Ayrıca bu metot, yukarıdaki encode() metodunu kullanarak yaptığımız dosyaya yazma işlemini biraz daha kolaylaştırabilir:
>>> import codecs
>>> f = codecs.open(“deneme.txt”, “w”, encoding=”utf-8″)
>>> f.write(u”ışık”)
>>> f.close()

Elbette codecs modülünün open() metodunu sadece yeni dosya oluşturmak için değil, her türlü dosya işleminde kullanabilirsiniz. Bu metot, dosya işlemleri konusunu işlerken gördüğümüz open() metoduyla birbirine çok benzer. Tıpkı o metotta olduğu gibi codecs.open() metodunda da dosyaları “w”, “r”, “a” gibi kiplerde açabilirsiniz.


%d blogcu bunu beğendi: