Bu yazımızın konusu string sınıfında silme işlemleri
Standart string sınıfının erase işlevi 3 ayrı imzayla yüklenmiş:
1 2 3 |
string& erase (size_type pos = 0, size_type len = npos); iterator erase (const_iterator p); iterator erase (const_iterator first, const_iterator last); |
Üç işlevi de ayrıntılı olarak inceleyeceğiz. Önce işlevlere şöyle genel olarak bir bakalım:
1 |
string& erase (size_type pos = 0, size_type len = npos); |
İşlevin geri dönüş değeri *this nesnesi. Yani işlevimiz üzerinde silme işlemi yapılan string nesnesinin kendisini döndürüyor. Bu işlev ile bir yazının dilediğimiz bir parçasını silebiliriz. İşlevin birinci parametresi silinecek yazı parçasının başladığı yerin indisi, ikinci parametresi ise silinecek parçanın uzunluğu. İkinci parametre için varsayılan arguman kullanılırsa verilen indisten başlayarak yazının geri kalan tüm karakterleri siliniyor. Birinci parametreye varsayılan arguman geçildiğinde ise silme işlemi 0 indisinden başlatılıyor. İşlevin her iki parametre değişkeni de varsayılan arguman (default argument) aldığından aslında bu işlevi üç ayrı işlev olarak düşünebiliriz:
1 2 3 |
string& erase (); //1 string& erase (size_type idx); //2 string& erase (size_type idx , size_type len); //3 |
Birinci işlev ile yazının tamamını,
İkinci işlev ile yazının idx indisli karakterinden başlayan geri kalan kısmını,
Üçüncü işlev ile yazının idx indisli karakterinden başlayan len uzunluğundaki parçasını silebiliriz.
Aşağıdaki koda bakalım:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> #include <string> using namespace std; int main() { string s{ "bukalemun" }; s.erase(7); cout << "(" << s << ")" << endl; s.erase(0, 2); cout << "(" << s << ")" << endl; s.erase(1, 2); cout << "(" << s << ")" << endl; s.erase(); cout << "(" << s << ")" << endl; // } |
İkinci işlevimiz aslında STL kaplarındaki temel silme işlevlerinden biri. string‘in de tam uyumlu bir STL kabı olduğunu hatırlayalım.
1 |
iterator erase (const_iterator p); |
Bu işlev ile herhangi bir adımlayıcı konumundaki karakter silinebilir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <string> #include <iostream> using namespace std; int main() { string s{ "kalem" }; s.erase(s.end() - 1); cout << "(" << s << ")" << endl; s.erase(s.begin()); cout << "(" << s << ")" << endl; return 0; } |
Yukarıdaki kodda s string nesnesinin tuttuğu yazının ilk ve son karakterleri siliniyor.
Üçüncü işlevimiz de STL kaplarının hemen hepsinde olan bir silme işlemlerinden biri. Bu işlev kap içindek bir aralığı (range) siliyor.
1 |
iterator erase (const_iterator beg, const_iterator end); |
Aşağıdaki kodda bir stringin tuttuğu yazının ilk ve son karakterleri dışındaki tüm karakterleri siliniyor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <string> #include <iostream> using namespace std; int main() { string s{ "anlamak" }; s.erase(s.begin() + 1, s.end() - 1); cout << "(" << s << ")" << endl; return 0; } |
Adımlayıcı parametreli silme işlevlerini geri dönüş değerleri yine adımlayıcı. Bu işlevler eğer en az bir karakter silinmiş ilk öğenin silme işleminden önceki konumunu döndürüyorlar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <string> #include <iostream> using namespace std; int main() { string str{ "kesin" }; str.insert(str.erase(str.begin() + 1, str.end() - 1), 'a'); cout << str << endl; return 0; } |
Yukarıdaki kodda “kesin” yazısından silinen “esi” yazısının yerine ‘a’ karakteri ekleniyor.
Yazıdan tek bir karakter silmek için hem indis parametreli hem de adımlayıcı parametreli işlevler çağrılabilir. string sınıfının adımlayıcıları random acces iterator kategorisinde olduğu için toplama çıkarma işlemleriyle adımlayıcı değerinden indis değerine indis değerinden adımlayıcı değerine geçilebilir. s bir string nesnesi olmak üzere s nesnesinin tuttuğu yazının idx indisli karakterine ilişkin adımlayıcı
1 |
s.begin() + idx |
değerindedir. Yine iter, s stringinin tuttuğu yazıda bir konumu göstermek üzere bu konuma ilişkin karakterin indisi
1 |
iter - s.begin() |
değerindedir.
yazıdan istenen bir karakteri silmek
Yazıdan istenen belirli bir karakteri silmek için string sınıfının find işlevi ile karakter aranır. find işlevi, aranan karakter bulunursa aranan karakterin indisini döndürür. Aranan karakter bulunamaz ise işlevin geri dönüş değeri string::npos değeridir. Aranan karakterin bulunması durumunda string sınıfının size_type parametreli işleviyle ya da adımlayıcı parametreli işleviyle yazıdan bulunan karakter silinebilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> #include <string> using namespace std; int main() { string s; cout << "bir yazi girin : "; getline(cin, s); cout << "silinecek karakteri girin "; char c; cin >> c; string::size_type idx; if ((idx = s.find(c)) != string::npos) { s.erase(idx, 1); cout << idx << " indisli oge silindi\n"; cout << s << endl; } else { cout << "aranan karakter bulunamadi" << endl; } } |
Yazıdan belirli değerdeki tüm karakterleri silmek ya da belirli koşulları sağlayan tüm karakterleri silmek için remove – erase idiyomu kullanılabilir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> #include <string> #include <algorithm> using namespace std; int main() { string s{ "ankara'dan babam aradi" }; s.erase(remove(s.begin(), s.end(), 'a'), s.end()); cout << "(" << s << ")" << endl; // } |
Aşağıdaki kodda ise yazıdaki tüm rakam karakterlerinin silinmesi için remove_if algoritması kullanılıyor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> #include <string> #include <algorithm> #include <cctype> using namespace std; int main() { string s{ "92n3e88c4a1t5i5427 e5r81g6i5n238" }; s.erase(remove_if(s.begin(), s.end(), &isdigit), s.end()); cout << "(" << s << ")" << endl; // } |
STL’in remove, remove_if, unique isimli silme işlevleri gerçek silme işlemi yapmazlar. Bu işlevler aldıkları aralık içinde yalnızca silinmemiş öğelerin bulunduğu bir aralık oluşturacak şekilde kap öğelerini yeniden konumlandırırlar. Bir kaptan öğe silmenin tek yolu kabın silme işlemi yapan üye işlevlerini çağırmaktır. Parametre değişkenleri adımlayıcı olan STL algoritmalarının kapların silme işlevlerini çağırması mümkün olmadığından gerçek silme işlemi yapmaları da mümkün değildir. Bu işlevler geri dönüş değerleriyle “logic end” konumu döndürürler. logic end konumu silinmemiş öğelerin yer aldığı aralığın end konumudur. Böylece bu algoritmalara çağrı yapan kodlar dilerlerse silinmesi istenen öğelere silinmiş muamalesi yaparak gerçek silme işlemi yapmadan silinmemiş öğeleri kullanabilir. Gerçek silme işlemi için string sınıfının aralık (range) parametreli erase işlevi (logic end – gerçek end) aralığıyla çağrılmalıdır.
Yazının tamamını silmek
Bir string nesnesini boşaltmanın yani string nesnesinin tuttuğu yazının tamamını silmenin birçok farklı yolu vardır:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <string> #include <iostream> using namespace std; int main() { string s1, s2, s3, s4, s5; s1 = s2 = s3 = s4 = s5 = "Necati"; s1.clear(); s2 = ""; s3.resize(0); s4.erase(); s5.erase(s5.begin(), s5.end()); cout << s1 << s2 << s3 << s4 << s5; return 0; } |
Standart string kütüphanesinde yazının başındaki ya da sonundaki boşluk karakterlerini silecek trim işlevleri yok. Şimdilik bu işlevleri yazmayı birer çalışma sorusu olarak okuyucuya bırakıyorum:
1 2 3 |
std::string & ltrim(std::string &r); std::string & rtrim(std::string &r); std::string & trim(std::string &r); |
ltrim işlevi yazının başındaki boşluk karakterlerini silecek.
rtrim işlevi yazının sonundaki boşluk karakterlerini silecek.
trim işlevi hem yazının başındaki hem de sonundaki boşluk karakterlerini silecek.