String Değişkenleri
Emre S. Tasci emre.tasci@hacettepe.edu.tr
Şu ana kadar Octave ile ağırlıklı (neredeyse istisnasız) olarak sayılar üzerine çalıştık ki, Octave'ın mühendislik uygulamalarında kullanmak üzere geliştirildiğini düşünürsek bu zaten beklenen bir şeydi. Fakat bazen, özellikle de başka programlarda kullanacağımız çıktılar oluşturmak istediğimiz zaman, çıktımızı belirli bir biçimde sunmak isteriz. printf()
fonksiyonunu bu işler kullanabileceğimizi gördük ama şimdiye kadar ele aldığımız tüm kullanımlarda yazı kısmı sabit olup, sayısal değerler değişiyordu, örneğin:
for i = 3:8
printf("Elimizdeki sayi: %d --> Bu sayi ",i)
if(mod(i,2)==0)
printf("cift bir sayidir.\n");
else
printf("tek bir sayidir.\n");
endif
endfor
Octave'da -çok gelişmiş olmasa da- sözcükler ve harfler için de bir değişken türü vardır. Harf dizilerinden (sözcük) ve sözcük takımlarından (cümle) oluşan bu değişkenler string değişkeni olarak adlandırılırlar. Tanım itibarı ile dizidirler.
String değişkenleri tırnak (") içinde tanımlanır.
isim = "Batuhan"
şeklinde değeri "Batuhan" olan, isim
adında bir string değişkeni tanımladığımızda, bu aslıdan 7 elemanı olan bir dizidir. Bir sayı dizisinin çeşitli elemanlarına nasıl ulaşabiliyorsak, string değişkeninin (harf dizisinin) elemanlarına da aynı şekilde ulaşabiliriz:
isim(2) % 2. eleman (harf)
isim(4:6) % 4.,5.,6. harfler
isim(5:end-1) % 5. harften sondan bir önceki harfe kadar
isim(1:2:7) % 1. harften 7. harfe bir atlayarak (2 ekleyerek)
isim(3:-1:1) % 3. harften 1. harfe geriye doğru
Her harfin bir sayısal değeri vardır, bu değerler için ASCII standardı verilen bir değerler tablosu kullanılır. Örneğin "A" karakterine 65; "B"ye 66; "a"ya 97; "b"ye 98 karşılık gelir. Bu karşılıkları printf'e bir string değişkeni besleyip, çıktıyı tam sayı olarak isteyerek görebiliriz:
str1 = "ABCabc";
printf("%d\n",str1);
ASCII tablosu 128 (2^7) değerden oluşup, 60'lı yıllarda bilgisayar sistemleri arasında uyum olması için standartlaştırılmıştır. Sadece yazılı karakterleri değil, bilgisayara verilecek işaretleri ("satır sonu", "sekme", "escape (çıkış) sinyali", vs.) de içerir: Kaynak: Wikipedia
Sonrasında (günümüzde) UTF-8 standardı kabul edilip, öntanımlı karakter sayısı 1112064'e çıkarılmıştır (UTF-8'in ilk 128 karakteri ASCII tablosuna karşılık gelmektedir -- aslında Octave'da UTF-8 desteği vardır -yani Türkçe karakterleri de destekler- ama işleri karıştırmamak adına 128'lik ASCII'de duracağız ;).
Sayısal değerleri char
komutu ile harflere dönüştürebiliriz. Örneğin, yukarıdaki tablodan bakarak "Fiz219" yazalım (rakamların da tıpkı harfler gibi farklı indislere sahip olduğuna dikkat edin -- mesela 1 -> 49):
dizi = [70, 105, 122, 50, 49, 57];
str2 = char(dizi)
Bu sayı <-> harf karşılığından ötürü, harf dizimizi doğrudan dizi olarak da tanımlayabilirdik:
str3 = ["F", "i", "z", "2", "1", "9"]
Neyse ki, her seferinde bu kadar uğraşmamak için, başta gösterdiğimiz tırnak içinde tanım yöntemi var:
str4 = "Fiz219"
Aynı şekilde, tırnak(") yerine kesme (') işareti de kullanılabilmektedir.
İki sayıyı büyüklük, küçüklük ve eşitlik kriterleri ile nasıl kıyaslayabileceğimizi biliyoruz: <,>,==,!=,<= ve >= operatörleri ile. Bu operatörleri harf bazında string değişkenlerine de uygulayabiliriz:
% "a", "b"den büyük mü (yani sonra mı geliyor)?
"a" > "b"
% "a", "b"den küçük mü (yani önce mi geliyor)?
"a" < "b"
% "a", "b"ye eşit mi (yani ASCII tablosunda aynı yerde mi)?
"a" == "b"
İşler buraya kadar iyi idi, hatta bu değerleri değişkenlere atadığımızda da yolunda gidiyor gibi görünüyor:
str5 = "a"
str6 = "b"
str5 > str6
str5 < str6
str5 == str6
Fakat, string değişkenlerimiz birden fazla harften oluştuğu zaman işler biraz karışıyor:
str7 = "Bilgisayar "
str8 = "Programlama"
str7 > str8
Aslında karışan bir şey yok, Octave, kendinden beklendiği üzere, verilen iki diziyi (string değişkenlerinin harf dizileri olduğunu hatırlayın), eleman bazında kıyaslıyor. Burada aslında şu soruyu sormuş olduk: "Bilgisayar " kelimesinin (harf dizisinin) hangi harfleri alfabede (ASCII Tablosunda) "Programlama" kelimesinde karşılık gelen harften sonra yer almaktadır? Cevap olarak bize verdiği: "1" (Doğru) olarak döndürülen, 6.,8. ve 10. harfler, yani: "s","y" ve "r" harfleri:
str7(str7>str8)
Octave açısından "Bilgisayar " ve "programlama" kelimelerini kıyaslamakla, [66, 105, 108, 103, 105, 115, 97, 121, 97, 114, 32] ile [112, 114, 111, 103, 114, 97, 109, 108, 97, 109, 97] dizilerini kıyaslamak arasında hiçbir fark yok.
Bunu görünce, iki string değişkeninin birbirine eşitliğinin sorgulanmasının da pek istediğimiz gibi sonuçlanmayacağı ortada. Nitekim:
str7 == str8
evet, gerçekten de iki kelimenin 4. ("g") ve sonran iki önceki "a" harfleri birbirine eşit ama bizim aklımızdaki iki kelimenin tümüyle birbirine eşit olup olmadığı idi. Tabii ki bunu, verilen bir dizinin tüm elemanlarının sıfırdan farklı olup olmadıklarını döndüren any()
fonksiyonunu kullanarak 2 adımda yapabiliriz ama her seferinde bu kadar uğraşmayalım diye, strcmp()
(Sözcük kıyasla: "{str}ing
{c}o{mp}are") diye bir fonksiyon üretmişler:
% str7 değişkeninde tutulan kelime, str8'dekiyle aynı mı?
strcmp(str7,str8)
Hazır strcmp'u kullanmaya başlamışken, yukarıda farklı farklı şekillerde tanımladığımız string değişkenlerinin birbirlerine eşitliğini de kontrol edelim:
dizi = [70, 105, 122, 50, 49, 57];
str2 = char(dizi)
str3 = ["F", "i", "z", "2", "1", "9"]
str4 = "Fiz219"
strcmp(str2, str3)
strcmp(str3, str4)
Görüldüğü üzere, tanım yöntemleri birbirine eşdeğer. Bir de büyük/küçük harf olayı var. Biliyoruz ki, büyük harflerle küçük harfler ASCII tablosunda farklı yerlere karşılık geldiğinden (örn: "A" : 65 & "a" : 97) eşitlik olmayacak ama bu da çoğu zaman çok da arzu ettiğimiz bir şey değil. Bu işin de üstesinden -en azından İngiliz alfabesindeki harflerde- büyük/küçük harf ayrımı yapmayan strcmpi()
fonksiyonu geliyor (sondaki "i", Büyük/küçük durumu yoksay'ın İngilizcesi {i}gnore case'den geliyor):
str4 = "Fiz219"
str9 = "FIZ219"
str10 = "FIz219"
strcmp(str4,str9)
strcmp(str4,str10)
strcmpi(str4,str9)
strcmpi(str4,str10)
str1 = "Merhaba"
str2 = "Dünya!"
şeklinde iki değişkenimiz olsun, biz de "Merhaba Dünya!" şeklinde bunların birleşimi olan üçüncü bir değişken kurmak istiyoruz. Birinci yöntem, klasik, string'leri harf dizisi olarak ele almak, nasıl ki iki diziyi köşeli parantezler içerisinde toplayıp birleştirebiliyorduk, burada da çalışması lazım:
sayi1 = [1 2 3]
sayi2 = [5 6 7]
sayi3 = [sayi1 sayi2]
Harf dizilerimize de uygulayalım bakalım:
str1 = "Merhaba"
str2 = "Dünya!"
str3 = [str1 str2]
Kelimelerin birbirine yapışık olması dışında fena değil! Araya koyacağımız boşluğu da bir eleman olarak ele alıp bir daha deneyelim:
str3 = [str1 " " str2]
Yine çok uğraştırmamak adına, Octave'da bu birleştirme işlerini yapan öntanımlı bir fonksiyon da mevcuttur: strcat()
(string birleştir : {str}ing con{cat}anate)
str4 = strcat(str1,str2)
% sondaki bosluklar, sekmeler, vs. strcat tarafindan yoksayilir:
str5 = strcat("Merhaba ","Dunya")
% bastaki bosluklar, sekmeler, vs. strcat tarafindan ele alinir:
str6 = strcat("Merhaba"," Dunya")
Eğer sondaki boşlukları korumak istiyorsanız, cstrcat()
komutunu kullanabilirsiniz:
strcat("Merhaba ","Dunya")
cstrcat("Merhaba ","Dunya")
disp("-----------------")
strcat("Merhaba"," ","Dunya")
cstrcat("Merhaba"," ","Dunya")
Çıktı biçimlemede sıkça kullandığımız printf()
fonksiyonumuz, şaşırtıcı olmayan bir biçimde, sayılara ilave olarak string değişkenlerini de destekler. Yapmamız gereken, değişkenimizin string olacağını belirtmek için '%s' yertutucusunu kullanmaktır:
printf("Dersimizin adi: %s.\n","FIZ219 - Bilgisayar Programlama");
Çok da faydalı bir şey olacakmış gibi görünmüyor ama bir de şu kullanımına bakalım: baştaki tek/çift ayırıcısını hatırlayın, onu bir daha yazalım:
for i = 3:8
if(mod(i,2)==0)
tekcift = "cift";
else
tekcift = "tek";
endif
printf("Elimizdeki sayi: %d --> Bu sayi %s bir sayidir.\n",i,tekcift)
endfor
Madem printf()'i kullanıyoruz, onun nimetlerinden de faydalanabiliriz, örneğin sabit bir yer ayırabiliriz veya sağa/sola yaslayabiliriz:
str = "Deneme";
printf("Denemeye 10 karakter ayarlayalim:%10s.\n",str) % Saga yaslanmis
printf("Denemeye 10 karakter ayarlayalim:%-10s.\n",str)% Sola yaslanmis
Sizce printf
fonksiyonunun çıktısı nedir? İçinde harfler var, dolayısıyla doğru tahmin ettiniz: printf, string türünde çıktı verir!
Fakat verdiği bu çıktı, sadece ekrana yazdırmak içindir. Bu farkı anlamak için aşağıdaki fonksiyonu inceleyelim:
function f = topla(a,b)
a+b
endfunction
topla(3,5)
Görünürde gayet eli yüzü düzgün bir fonksiyon olup, verilen iki sayıyı topluyor. Peki, biz o toplamı alıp bir başka yerde kullanabiliyor muyuz? Düşünün bakalım...
Maalesef hayır, çünkü fonksiyonun döndürdüğü hiçbir değer yok! Hesabı yapmasına yapıyor ama döndürmüyor. Yani:
deyince, bir ihtimal tahmininizin aksine, toplam
değişkeninin değerini 8 yapmıyor (ekrana 8 yazsa dahi):
toplam = topla(3,5)
Fonksiyona tekrar baktığımızda, dönüş değerini (bu örnekte "f") tanımlamamış olduğumuzu fark ediyoruz, doğrusu şöyle olmalıydı:
function f = topla(a,b)
f = a+b
endfunction
toplam = topla(3,5)
printf
'in yaptığı da buna benzer bir şey: kendisine verilen değişkenleri güzelce biçimler, ekrana yazar ama döndürdüğü değer aslında ekrana yazdığı şey değil de, toplam karakter sayısıdır:
str1 = "Merhaba"
str2 = "Dunya!"
% Merhaba Dunya!
% 12345678901234 : Bastan sona toplam 14 karakter
donus_degeri = printf("%s %s",str1,str2)
...keşke printf
le yazdığımız string çıktılarını ekrana değil de, bir string değişkenine yönlendirebileceğimiz bir yol olsaydı... Aaaa, böyle bir yol var aslında! sprintf()
fonksiyonu!!!
str1 = "Merhaba"
str2 = "Dunya!"
donus_degeri = sprintf("%s %s",str1,str2)
donus_degeri
Bu şekilde artık istediğimiz -hemen hemen- her şeyi yapabiliriz, mesela:
printf("%s %s %s\n",donus_degeri,donus_degeri,donus_degeri)
(Bu yukarıdaki örnek çok da aydınlatıcı olmadı, şunu deneyelim bir de:)
function f = merhaba(isim)
f = sprintf("Merhaba %s!\n",isim);
endfunction
md = merhaba("Dunya")
me = merhaba("Emre")
Daha gelişmişini size "meydan okuma" olarak vereyim:
Verilen 4 basamaklı bir sayıyı yazı olarak döndüren bir fonksiyon yazın.
Örneğin:
sayi2yazi(1234)
-> "bin iki yüz otuz dört"
döndürsün.