Witam. Standardowa Biblioteka Szablonów C++ (STL) oferuje nam typ string, posiadający wiele przydatnych metod, dzięki którym będziemy mogli czynić przeróżne cuda z naszym tekstem. Ale po kolei. W STL zdefiniowany jest szablon klasy basic_string, którego argumentem jest typ znaków, jaki będzie on przechowywał – możemy więc posiadać string, w którym znaki są typu char (8 bitów), typu wide char (16 bitów) lub innego. Szablon ten zawiera w sobie wiele ciekawych i przydatnych metod, które dają duże możliwości w manipulowani stringami. Zdefiniowanych zostało też kilka operatorów, aby praca z nimi była wygodniejsza.
Należy pamiętać, że tych stringów nie wolno mylić ze stringami, które są zakończone znakiem o kodzie 0 (NULL) – w stringach z STL zapamiętywana jest ilość aktualnie przechowywanych znaków, więc znak NULL nie jest potrzebny.
Typ, jakim będziemy się posługiwać, to wyspecjalizowany typ szablonu basic_string, w którym znaki są typu char:
1 |
typedef basic_string string; |
Do użytku oddany jest także typ, w którym znaki są typu wide char:
1 |
typedef basic_string wstring; |
Te typy mają także swoje własne metody oraz operatory, przydatne podczas pracy na nich.
Aby móc korzystać z tych dobrodziejstw, musimy włączyć do naszego programu nagłówek string:
1 |
#include |
Typy te znajdują się w przestrzeni nazw std, więc przy definiowaniu zmiennych należy się posłużyć odpowiednim przedrostkiem:
1 |
std::string moj_tekst ; |
Dla wygody, na początku programu dodamy dyrektywę karzącą domyślnie dodawać przedrostek std:
1 |
using namespace std ; |
To tyle słowem wstępu ;]
String oferuje nam kilka konstruktorów (po dokładniejszy opis odsyłam do MSDN):
1 2 3 4 5 6 7 8 9 |
string(); string(const char* _Ptr, size_type _Count); string(const char* _Ptr); string(const string& _Right, size_type _Roff = 0, size_type _Count = npos); string(size_type _Count, char _Ch); |
_Ptr – ciąg znaków zakończonych znakiem NULL (argumentem nie może być sama wartość NULL)
_Count – liczba znaków, jakimi string ma być zainicjalizowany (pobierane z argumentów _Ptr oraz _Right)
_Right – string, którego znakami ma być zainicjalizowany nasz string
_Roff – pozycja w _Right, od której należy pobrać _Count znaków
_Ch – znak, jakim ma być wypełniony string
Kilka przykładów:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
string s1("Niezly hardkor." , 6) ; // s1 = "Niezly" string s2("Niezly hardkor.") ; string s3 = "abc" ; // można i tak, ale to jest już przypisanie, a nie inicjalizacja string s4(s2) ; // 4. konstruktor string s5(s2 , 7 , 7) ; // s5 = "hardkor" string s6(10 , 'u') ; // s6 = "uuuuuuuuuu" ; string s7 ; s7 = "unit1" ; |
Pytanie: co zawiera w sobie po utworzeniu string s4? Pustą wartość? Nie, gdyż domyślnie w trzeciem konstruktorze _Count = npos, które jest równe -1 i oznacza albo „nie znaleziono” lub „wszystkie znaki”, więc s4 zostanie zainicjalizowany wszystkimi znakami ze stringu s1.
Iteratory zostały stworzone specjalnie na potrzeby biblioteki STL. Można je przesuwać jak wskaźniki itp. Do wyboru mamy kilka iteratorów, jak np. iterator oraz reverse_iterator – pierwszy z nich pozwala odczytywać i modyfikować elementy wektora, a drugi pozwala na to samo, tylko, że w odwróconym wektorze. Wartość wskazywanego elementu pozyskujemy za pomocą operatora wyłuskania (*). Występują także wersje iteratorów, które mogą jedynie odczytywać wartości – const_iterator oraz const_reverse_iterator. Iteratory definiujemy w następujący sposób:
1 2 3 4 5 |
string str("kom") ; string::iterator mojIterator ; string::const_iterator mojStalyIterator ; |
Użycie:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
mojIterator = str.begin() ; // ustawiamy iterator na 1. znak *mojIterator = 'd' ; // zmieniamy 1. znak na 'd' cout << "\n" << *mojIterator ; mojStalyIterator = str.begin() ; // staly iterator tez ustawiamy na poczatek // *mojStalyIterator = 'd' ; // blad! cout << "\n" << *mojStalyIterator ; // wypisujemy po kolei wszystkie znak, jeden pod drugim for (mojIterator = str.begin() ; mojIterator != str.end() ; mojIterator++) cout << "\n" << *mojIterator ; |
Istnieje wiele funkcji, które zwracają nam pozycję w stringu właśnie za pomocą iteratorów, jak np. begin().
Do wykorzystania mamy kilka operatorów:
= służy do przypisania stringowi nowej wartości:
1 2 3 |
string s ; s = "Niezly" ; // można też s = 'a' bądź s = s7 ; |
+= operator, za pomocą którego doklejamy do stringu nowy łańcuch znaków:
1 |
s += " hardkor." ; // s = "Niezly hardkor." |
[] operator, za pomocą którego odwołujemy się do poszczególnych znaków w stringu (są one numerowane od 0!). Uwaga: skutki podania nieprawidłowego indeksu (mniejszego od 0 bądź większego od maksymalnego) są niezdefiniowane, więc w razie niepewności należy stosować metodę at(), jednakże operator [] jest szybszy w działaniu od tejże metody.
1 |
s[0] = 'a' ; // odwołanie do pierwszego znaku; nie wolno s[0] = "a" ! |
!= sprawdza, czy string po prawej stronie operatora jest różny od tego z lewej strony. Uwaga: brana jest pod uwagę wielkość liter!
1 2 3 4 5 |
s = "unit1" ; if (s[0] != 'a') cout << "rozne od u" ; if (s != "unit5") cout << "rozne od unit5" ; |
== sprawdza, czy porównywane stringi są takie same. Uwaga: brana jest pod uwagę wielkość liter!
< porównuje dwa stringi i zwraca prawdę, jeżeli string z lewej strony jest „mniejszy”:
1 2 3 4 5 6 7 8 9 |
string str1("tes") , str2("test") ; if (str1 < str2) cout << "str1 mniejszy" << endl ; str1 = "TEST" ; str2 = "test" ; if (str1 < str2) cout << "str1 mniejszy" << endl ; |
Zobaczy komunikat dwa razy. Sprawdzane są tutaj kolejne znaki, a mniejszy jest ten znak, którego kod ASCII jest mniejszy, czyli porównując 'A’ oraz 'a’ wyjdzie, że 'A’ jest mniejsze ;] Poza tym, jeżeli string pierwszy ma taki sam człon jak drugi, ale jest od niego krótszy, to także jest on mniejszy.
> jak powyżej, ale tym razem prawda jest zwracana, jeżeli pierwszy string jest “większy”.
<= sprawdza, czy string z prawej strony jest mniejszy bądź równy temu z prawej strony operatora.
>= testuje, czy prawy string jest większy bądź równy od lewego.
<< wstawia string do strumienia:
1 |
cout << s ; |
>> wyjmuje dane ze strumienia i przypisuje je do stringu:
1 |
cin >> s ; |
+ operator ten łączy ze sobą dwa stringi:
1 2 3 4 5 |
s = str1 + str2 ; s = str1 + "tekst" ; // s = "Niezly" + " hardkor" ; tak nie wolno |
Do pracy na stringach mamy kilkanaście ciekawych metod i po kilka ich odmian. Oto one:
append
Funkcja ta dodaje do końca stringu inny:
1 2 3 4 5 6 7 8 9 10 11 |
string& append(const char* _Ptr); string& append(const char* _Ptr, size_type _Count); string& append(const string& _Str, size_type _Off, size_type _Count); string& append(const string& _Str); string& append(size_type _Count, char _Ch); string& append(InputIterator _First, InputIterator _Last); |
Parametry:
_Ptr – string zakończony znakiem NULL (tak zwany C-string),
_Count – określa, ile znaków ma zostać dodanych,
_Str – string, który ma zostać dodany,
_Off – wyznacza początek pod-stringu z _Str, który ma zostać dołączony,
_Ch – znak, jaki ma być dodany _Count razy,
_First i _Last – wyznaczają początek i koniec pod-stringu danego stringu, który ma zostać dodany.
Przykłady:
1 2 3 4 5 6 7 8 9 |
s = "Ala ma" ; s.append("kota, bo kot ma wszystkie sezony StarGate.") ; // s = "Ala ma kota, bo kot ma wszystkie sezony StarGate. " s = "Ala ma" ; s.append(" kota, bo kot ma wszystkie sezony Stargate" , 5) ; // s = "Ala ma kota" s.append(3 , '!') ; // s = "Ala ma kota!!!" |
Przypisuje stringowi nową wartość:
1 2 3 4 5 6 7 8 9 10 11 |
string& assign(const char* _Ptr); string& assign(const char* _Ptr, size_type _Count); string& assign(const string& _Str, size_type off, size_type _Count); string& assign(const string& _Str); string& assign(size_type _Count, char _Ch); string& assign(InputIterator _First, InputIterator _Last); |
Parametry:
_Ptr – przypisuje string zakończony znakiem NULL (tak zwany C-string),
_Count – określa, ile znaków ma zostać przypisanych,
_Str – string, który ma zostać przypisany,
_Off – wyznacza początek pod-stringu z _Str, który ma zostać przypisany,
_Ch – znak, jaki ma być przypisany _Count razy,
_First i _Last – wyznaczają początek i koniec pod-stringu danego stringu, który ma zostać przypisany.
Przykłady:
1 2 3 4 5 6 7 |
string str("Niezly hardkor!") ; s.assign(str , 7 , 8) ; // s = "hardkor" cout << s << endl ; s.assign(str.begin() , str.begin() + 6) ; // s = "Niezly" ; |
Zwraca referencję do znaku o indeksie loc:
1 2 3 |
char& at( size_type loc ); const char& at( size_type loc ) const; |
Kolejne znaki numerowane są od 0 do n – 1, gdzie n to ilość znaków w stringu.
Jedynym parametrem jest właśnie indeks znaku, który chcemy otrzymać. Metoda ta jest wolniejsza od operatora [], ale uwaga: używanie tej metody jest bezpieczniejsze od używania operatora [], gdyż sprawdza ona, czy indeks jest nieprawidłowy – czy nie jest mniejszy od zera bądź większy od maksymalnego indeksu, jeżeli tak będzie, zostanie wywołany wyjątek out_of_range.
Przykład:
1 2 3 4 5 6 7 |
string str("Niezly hardkor!") ; for (int i = 0 ; i < str.size() ; i++) cout << str << endl ; str[0] = 'n' ; |
Zwraca iterator do pierwszego znaku stringu (bądź do miejsca zaraz za końcem stringu, jeżeli ten jest pust):
1 2 3 |
const_iterator begin( ) const; iterator begin( ); |
Przykład:
1 2 3 4 5 6 7 8 9 |
string str("Niezly hardkor!") ; string::iterator it ; it = str.begin() ; cout << *it << endl ; // wypisujemy pierwszy znak, czyli 'N' cout << *(it + 5) << endl ; // przesuwamy się o 5 - znak 'y' |
Zwraca wskaźnik na zakończony znakiem NULL string (w stylu C). Nie można modyfikować tak przesłanego stringu, więc można go przesyłać jedynie do funkcji, które jako argumenty przyjmują const *char:
1 |
const char *c_str( ) |
Przykład:
1 2 3 |
string str("mojplik.txt") ; ofstream plik(str.c_str()) ; // konstruktor ofstream jako wymaga przeslania sciezki do pliku jako const char*, tutaj wkracza c_str() |
Zwraca maksymalną ilość elementów, jakie mogą być przechowywane bez konieczności zwiększanie rozmiaru zaalokowanej pamięci dla stringu:
1 |
size_type capacity( ) const; |
Przykład:
1 2 3 |
string str("Niezly hardkor") ; cout << str.capacity() << endl ; // zwroci liczbe 15 |
Usuwa wszystkie elementy ze stringu:
1 |
void clear( ); |
Przykład:
1 2 3 4 5 |
string str("Niezly hardkor") ; str.clear() ; cout << str ; // nie ukaze sie nam zaden tekst, bo str jest pusty |
Sprawdza, czy porównywane stringi są takie same, bądź czy jeden z nich nie jest większy/mniejszy od drugiego. Brana jest pod uwagę wielkość liter. Uwaga: małe litery są „większe” od wielkich, ponieważ ich kody ASCII są od większe. Zwracana wartość jest mniejsza od zera, jeżeli przesłany w parametrze string jest większy, zero, jeśli stringi są takie same oraz większa od zera, jeśli przesłany string jest mniejszy.
1 2 3 4 5 6 7 8 9 10 11 |
int compare(const string& _Str) const; int compare(size_type _Pos1, size_type _Num1, const string& _Str); int compare(size_type _Pos1, size_type _Num1, const string& _Str, size_type _Off, size_type _Count); int compare(const char* _Ptr) const; int compare(size_type _Pos1, size_type _Num1, const char* _Ptr) const; int compare(size_type _Pos1, size_type _Num1, const char* __Ptr, size_type _Num2 = npos) const; |
Parametry:
_Str – string, który ma zostać przyrównany,
_Pos1 – indeks znaku w stringu, na rzecz którego funkcja została wywołana, od którego ma zostać rozpoczęte porównywanie,
_Num1 – maksymalna ilość znaków ze stringu, na rzecz którego została wywołana funkcja, które mają zostać porównane,
_Num2 – maksymalna ilość znaków z przyrównywanego stringu, które mają zostać porównane
_Off – pozycja znaku w porównywanym stringu, od którego ma zostać rozpoczęte porównywanie,
_Count – maksymalna ilość znaków ze stringu porównywanego jakie mają zostać porównane,
_Ptr – string w stylu C, który ma zostać porównany.
Przykład:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
string str("") ; string str2("") ; // int compare(const string& _Str) const; cout << "Podaj pierwszy tekst:" << endl ; cin >> str ; cout << "Podaj drugi tekst:" << endl ; cin >> str2 ; int res = str.compare(str2) ; if (res < 0) cout << "Pierwszy string jest mniejszy od drugiego." << endl ; else if (res > 0) cout << "Pierwszy string jest wiekszy od drugiego." << endl ; else cout << "Stringi sa takie same." << endl ; // int compare(size_type _Pos1, size_type _Num1, const string& _Str); str = "www.unit1.pl" ; str2 = "unit1" ; // z www.unit1.pl zostanie wycięte "unit1" i porównane z "unit1", więc tekst "Takie same" zostanie wypisany if (str.compare(4 , 5 , str2) == 0) cout << "Takie same." << endl ; // int compare(size_type _Pos1, size_type _Num1, const string& _Str, size_type _Off, size_type _Count); str = "www.unit1.pl" ; str2 = "unit1.pl" ; // ze str zostanie porównane "unit1" ze stringiem wyciętym ze str2: "unit1", czyli znowu zobaczymy tekst "Takie same." if (str.compare(4 , 5 , str2 , 0 , 5) == 0) cout << "Takie same." << endl ; // te trzy funkcje zwroca wartosci 0, czyli znowu 3 razy zobaczymy tekst "Takie same." // int compare(const char* _Ptr) const; if (str.compare("www.unit1.pl") == 0) cout << "Takie same." << endl ; // int compare(size_type _Pos1, size_type _Num1, const char* _Ptr) const; if (str.compare(4 , 5 , "unit1") == 0) cout << "Takie same." << endl ; // int compare(size_type _Pos1, size_type _Num1, const char* __Ptr, size_type _Num2 = npos) const;[/ if (str.compare(4 , 5 , "unit1.pl" , 0 , 5) == 0) cout << "Takie same." << endl ; |
// z czasem będą się pojawiać nowy wpisy
- basic_string – opis szablonu basic_string w MSDN
- string – opis typu string w MSDN
- tutorial o STL – rozbudowany, godny uwagi anglojęzyczny tutorial o STLu
- dokumentacja STL – świetna, anglojęzyczna dokumantacja STL