30 Mart 2011 Çarşamba

İlkel Türler-Karakterler

İlkel türlere dair ikinci yazımızda metinsel öğelerin atomik parçası olarak düşünülebilecek simgelerin Java karşılığı olan karakter türüne—char'a—değineceğiz. Anlatımımıza, tamsayı türlerinden bahsederken üzerinde durmadığımız bir noktayı vurgulayarak başlayalım: ne tür bir değer temsil ediyorsak edelim, eninde sonunda her şeyin işlemci tarafından yorumlanabilen ikil (İng., bit) desenleri haline dönüştürülmesi gerekir. Örneğin, geçen yazımızın konusu olan tamsayı türleri 2'nin tümleyeni adı verilen bir temsil yöntemi kullanılarak ikillere dönüştürülür. Karakter tablosu olarak adlandırılan bir küme içinden seçilebilen karakterler—yani, metni oluşturan simgeler—için de benzer bir dönüşüm söz konusudur. Bu dönüşüm, karakter tablosundaki karakterler ile ikil desenleri arasındaki eşlemeyi tanımlayan bir karakter kodlaması yoluyla yapılır.

Değişik ortamlardaki karakterler için farklı kodlamaların kullanıldığı Java'da, Unicode tablosundan seçilen karakterler bellekte UTF-16 adı verilen bir kodlamaya göre temsil edilir. Bir diğer deyişle, karakterleri tutmakta kullanılan iki sekizli büyüklüğündeki char türüne ait bir tanımlayıcı, kendisine sağlanan Unicode karakterin UTF-16 kodlamasını tutar. Buna göre, aşağıdaki satırların işlenmesi sonrasında tanımlanan simgesel sabitler, sırasıyla, ilklemede kullanılan karaktere karşılık gelen 97, 305 ve 351 değerlerine sahip olacaktır.
final char aHarfi = 'a'; // aHarfi <- 97
final char ıHarfi = 'ı'; // ıHarfi <- 305
final char şHarfi = 'ş'; // şHarfi <- 351
Karakterlerin temsilinde kullanılan değerin eksi olmayan bir tamsayı olması, karakter sabitlerin ve karakter tanımlayıcıların tamsayı türüne sahipmiş gibi kullanılabileceği anlamına gelir. Ancak, anlaşılması ve bakımı zor kodlara neden olacağı için, bu özelliğin kullanımından olabildiğince kaçınılmalıdır. Ayrıca, tamsayı türlerinin 0-merkezli bir sayı çizgisindeki eksi ve artı sayıları temsil edebilirken, char türünün eksi olmayan tamsayıları temsil edebileceği unutulmamalıdır.
int sıraNo = 'a'; // sıraNo <- 97
sıraNo++;
char harf = (char) sıraNo; // harf <- 'b'
harf = (char) 67; // harf <- 'C'
char türlü bir tanımlayıcıya tamsayı değer sağlanmasının bir getirisi, klavyenizde bulunmayan Unicode karakterlerin girilmesine olanak tanımasıdır. Örneğin, matematiksel ifadelerin işlendiği bir metnin parçası olarak kullanmak isteyebileceğiniz sigma (Σ), klavyenizde bulunmadığı halde karşılığı olan 0x3A3—931 veya 03243 de olabilir—değerinin yazılmasıyla girilebilir.
final char sigma = '\u03A3'; // sigma <- 'Σ'
Dikkat edecek olursanız, yukarıda sağlanan örnek bir öncekinden farklı bir gösterim kullanıyor. \u önekinin derleyiciye verdiği ön bilgi sayesinde, bu gösterimin kullanıldığı durumlarda biçimlendirme yapmak gerekmiyor; derleyici \u öneki sonrasındaki sayıyı ilişkin karakterin Unicode tablosundaki konumunun 16'lı tabandaki dört basamaklı hali olarak ele alıyor ve bekleneni yapıyor.

Tamsayı değerlerin char türlü olarak ele alınabilmesinin bir diğer yararı, varlığı metnin görünümünde dolaylı bir biçimde etki yaratan kontrol karakterlerinin temsil edilmesinde ortaya çıkar. Örnek olarak, bir sonraki satırın başına geçiren yeni satır karakterini ele alalım. Bu karakter, metni okuyacak düzenleyici benzeri bir yazılım tarafından okunmalı ve hesaba katılmalı, fakat bu karakterin varlığı metni okuyan kişilere doğrudan yansıtılmamalıdır. Bundan dolayı, Unicode tablosunda 10. sırada yer alan bu karakter '\u000A' değeri ile temsil edilir. Sıklıkla kullanılan bu karakterin daha kolay yazımını sağlamak amacıyla algılaması daha kolay ikinci bir gösterim kullanılabilir: '\n'. Bu ve bazı diğer kontrol karakterleri aşağıdaki tabloda verilmiştir.

Özel gösterimli karakterler
Karakter adıGösterimKarakter
Geri alma'\b''\u0008'
Sayfa ilerletme'\f''\u000C'
Yeni satır'\n''\u000A'
Satır başı'\r''\u000D'
Sektirme'\t''\u0009'
Tek tırnak'\'''\u0027'
Tırnak'\"''\u0022'
Ters kesme'\\''\u005C'

Tablonun son üç sırasındaki karakterlerin, diğerlerinden farklı olarak, görsel gösterimli karakterler olduğunu fark etmişsinizdir. Kontrol karakteri sınıfına girmeyen bu karakterlerin bu şekilde kullanılması, söz konusu karakterlere Java'da yüklenen özel anlamdan kaynaklanır. Örneğin, karakter sabitlerinin başlangıç ve sonunu işaretlemek için kullanılan tek tırnak iminin bu görevi dışında kullanılabilmesi için özel ele alınması isteğimizin derleyiciye iletilmesi gerekir. Bu da, yukarıdaki tabloda belirtildiği gibi yapılacaktır.

Yazımızı, çok ufak bir olasılıkla da olsa, bazılarınızın canını yakabilecek bir ayrıntıya değinerek kapatalım: Başlangıcında iki sekizliye sığan indislerle kullanılabilen Unicode tablosu, zaman içinde yeni karakterlerin eklenmesiyle genişlemiş ve indis değerleri iki sekizliye sığmaz hale gelmiştir. Bu da, Unicode tablosundaki kimi karakterlerin iki sekizli yer tutan char türündeki bir tanımlayıcı ile temsil edilememesi durumunu doğurmuştur. Yeryüzünde konuşulmakta olan modern dillerin simgeleri için geçerli olmayan bu durumun, nadiren de olsa sürprizler yaratabileceği unutulmamalıdır. Örneğin, müzik gösteriminde yararlanılan simgelerin kullanımı unutkan bir programcıya bu durumu hatırlatacaktır. Zira, bu tablodan da görüleceği gibi, müziksel simgeler Unicode tablosunun 0x1D100 ile 0x1DFF nolu indisleri arasında bulunur ve ancak dört sekizli ile temsil edilebilir. İşin kötüsü, dört sekizli kaplayan bu alana ilişkin karakterin Unicode tablosundaki indis değeri değil UTF-16 kodlamasının ürettiği bambaşka bir değer konulması gerekecektir. Bu değerin ne olacağını merak edenlere UTF-16 kodlaması konusundaki şu Sıklıkla Sorulan Sorular belgesini okumalarını tavsiye ederim.