Klasa std::string

String u programskom jeziku C je niz znakova varijabilne duljine koji završava nul-znakom (\0) koji označava kraj stringa. Najčešće se alocira dinamički, a kretanje kroz njega se vrši pomoću pokazivača na prvi element, uporabom pokazivačke aritmetike.

U jeziku C++ stringove iz jezika C (C-stringove) zamijenjuje klasa std::string koja brine o dinamičkoj alokaciji i dealokaciji niza znakova te nudi veliki broj metoda za rad sa stringovima.

Klasa string je ustvari specijalizacija predloška klase basic_string<T>. U imeniku std imamo ove aliase:

namespace std{
   typedef basic_string<char> string;
   typedef basic_string<wchar_t> wstring;
}

Nizovne konstante, kao na primjer

auto x = "OP(C++)";

su C-stringovi, odnosno nizovi znakova završeni nul-znakom. Tip varijable x se deducira kao const char *. Najčešće ih možemo koristiti tamo gdje se traži std::string zato što postoji implicitna konverzija iz C-stringa u std::string.

Definicija i inicijalizacija stringova

Da bismo koristili klasu string iz standardne biblioteke moramo uključiti zaglavlje string.

#include <string>
using std::string;

String možemo inicijalizirati na različite načine. Na razini implementacije to znači da klasa string ima više verzija konstruktora. Ovdje su dani neki od njih:

string s1;                 // Konstruktor bez argumenata konstrira prazan string
string s2(s1);             // s2 je inicijaliziran kopijom stringa s1
string s3("ime i prezime");// s3 je inicijalizira konstantnim stringom
string s4(10,'x');         // s4 je inicijaliziran sa 10 znakova 'x'
  • Nul-znak (\0) nema posebno značenje u std::string klasi i string ga može sadržavati kao i svaki drugi znak.

  • Ako nekoj funkciji koja uzima C-string treba predati std::string onda koristimo metodu c_str() koja vraća reprezentaciju stringa kao niza znakova završenog nul-znakom:

void f(char * str){
// ...
}
// ...
std::string mystring;
// ...
f(mystring.c_str());

Povratna vrijednost c_str() funkcije je garantirano ispravna samo do poziva prve operacije na stringu koja ga može promijeniti.

Čitanje i pisanje stringova

Za čitanje stringova s tastature (standardni ulaz, std::cin) i njihovo ispisivanje na ekranu (standardni izlaz, std::cout) koristimo operatore << i >> kao u ovom primjeru:

cin >> s1;// Učitavanje stringa limitiranog bjelinama
cout << s1 << endl; // Ispis stringa

Prilikom učitavanja preskaču se početne bjeline, a učitavanje prestaje s prvom bjelinom. Operacije čitanja i pisanja mogu se ulančavati kao u ovom primjeru:

cin >> s2 >> s3;// Čita prvo s2, a zatim s3.
cout << s2 << s3 << endl; // Ispisuje prvo s2, a zatim s3.

Želimo li učitavati s ulaza sve dok ne naiđemo na kraj ulaznih podataka (end-of-file) trebamo koristiti sljedeću konstrukciju:

while(cin >> s1)
    cout << s1 << endl;

Ukoliko dođe do greške pri upisu, ili smo došli do kraja ulazne datoteke, cin >> s1 će vratiti false i tada izlazimo iz while petlje. (Pod Linuxom/Unixom treba upisati Return i Ctr-D kao znak za kraj datoteke.)

Ulazni operator ne može pročitati string koji sadrži bjeline pa je stoga korisna funkcija getline koja će pročitati čitavu liniju, sve do znaka za prijelaz u novi red koji se pročita i odbacuje. Na primjer,

while(getline(cin,s1))
    cout << s1 << endl;

Pri ispisu smo morali dodati endl jer znak za prijelaz u novi red nije učitan u s1.

Operacije na stringovima

U sljedećoj tabeli su navedene neke operacije koje možemo vršiti nad stringovima.

s.empty()

Vraća true ako je string prazan; inače false

s.size()

Vraća broj znakova u s

s[n]

Vraća referencu na znak na poziciji n. Prvi znak je na poziciji 0. Ne provjerava je li indeks u granicama.

s.at(i)

Isto što i s[n] ali provjerava je li indeks u granicama i izbacuje izuzetak.

s1 + s2

Vraća string koji je jednak konkatenaciji stringova s1 i s2.

s1 = s2

Zamijenjuje string s1 kopijom stringa s2.

s1 == s2

Ispituje jednakost stringova s1 i s2; true ako su jednaki, false ako nisu.

!=, < , <=, >, >=

Relacijski operatori provjeravaju leksikografski poredak.

Nadovezivanje jednog stringa na drugi (konkatenacija) vrši se pomoću operatora zbrajanja. Ti su operatori (+, +=) redefinirani u klasi string kako bi mogli biti primijenjeni na stringove.

string str1 = "AAA";
string str2 = "BBB";
string str3 = str1 + str2;// Konkatenacija dvaju stringova
string str4 = str3 + "\n";// Konkatenacija stringa i konstantnog znakovnog niza

str1 += str4; // Dodavanje stringa str4 na str1

for(string::size_type i=0; i < str4.size(); ++i)
    if( str4[i] == 'B') str4[i] = 'X';

Indeks koji treba koristiti za kretanje kroz string je tipa string::size_type.

String predstavljaja jedan sekvencijalni spremik, specijaliziran za držanje znakova. Kao i kod vektora, znakovi se čuvaju na uzastopnim lokacijama u memoriji što dozvoljava efikasno indeksiranje niza. String je stoga vrlo blizak spremniku vector i podržava operacije koje podržava vector.

Indeksirane operacije

String podržava operacije insert, erase i assign koje rade s iteratorima ili parovima iteratora, ali nudi i paralelne metode koje rade s indeksima umjesto iteratora. Te su operacije dane u sljedećoj tabeli u kojoj su pos i pos2 indeksi:

s.insert(pos, n, c)

Ubacuje n kopija znaka c ispred elementa indeksiranog s pos.

s.insert(pos, s2)

Ubacuje kopiju stringa s2 ispred znaka s pozicijom pos.

s.insert(pos, s2, pos2, len)

Ubacuje len znakova iz stringa s2, počevši od pozicije pos2, ispred znaka s pozicijom pos.

s.insert(pos, len, cp)

Ubacuje len znakova iz polja na koje pokazuje cp ispred znaka s pozicijom pos.

s.insert(pos, cp)

Ubacuje kopiju znakovnog niza na koji pokazuje cp (koji mora biti završen nul-znakom) ispred znaka s pozicijom pos.

s.assign(s2)

Zamijeni s s kopijom od s2.

s.assign(s2, pos2, len)

Zamijeni s s kopijom od len znakova iz s2 koji počinju na poziciji pos2.

s.assign(cp, len)

Zamijeni s s kopijom od len znakova iz polja na koje pokazuje cp.

s.assign(cp)

Zamijeni s sa znakovnim nizom (završenim nul-znakom) iz polja na koje pokazuje cp.

s.erase(pos, len)

Obriši len znakova polazeći od pozicije pos.

Sve operacije vraćaju referencu na s.

Neki primjeri su dani ovdje:

string s1("Dobar dan.");
string s2;
s2.assign(s1,6,3);            // s2 = "dan"
s2.assign(s1,2,string::npos); // s2 = "bar dan."
s2.assign(3,'v');             // s2 = "vvv"

s2.insert(0,s1);              // s2 = "Dobar dan.vvv"
s2.insert(10, s1, 6, 4);      // s2 = "Dobar dan.dan.vvv"
s2.insert(0, 3, 'x');         // s2 = "xxxDobar dan.dan.vvv"
s2.erase(8,4);                // s2 = "xxxDobar.dan.vvv"

std::string::npos služi kao oznaka za kraj stringa.

Substringovi

Iz svakog stringa možemo izvući odgovarajući podstring pomoću substr operacije. Operacija vraća kopiju novostvorenog stringa.

s.substr(pos, n)

Vraća string koji sadrži n znakova iz stringa s počevši od pozicije pos.

s.substr(pos)

Vraća string koji sadrži znakove od pozicije pos do kraja od s.

s.substr()

Vraća kopiju od s.

append i replace

Postoji više preopterećenih verzija funkcije append ifunkcije replace. Funkcija append dodaje znakove na kraj stringa; funkcija replace zamijenjuje raspon znakova drugim znakovima. Pri tome zamjena jednog skupa znakova drugim znači da se prvi skup briše (erase) i zatim se na to mjesto ubacuje novi skup znakova (insert).

Funkcije append i replace razlikuju se po načinu na koji se zadaje raspon znakova koje ubacujemo, a funkcije replace se razlikuju i po načinu zadavanja raspona elemenata koji se izbacuju (zamijenjuju) iz stringa. Metode su dane ovdje:

s.append(args)

Dodaj args na s. Vraća referencu na s.

s.replace(pos, len, args)

Izbaci len znakova iz s počevši od pozicije pos i zamijeni ih znakovima iz args. Vraća referencu na s. Ova verzija ne uzima args u obliku b2, e2.

s.replace(b, e, args)

Izbaci znakove u rasponu određenom s iteratorima b, e iz s i zamijeni ih znakovima iz args. Vraća referencu na s. Ova verzija ne uzima args u obliku s2, pos2, len2.

Argumenti args, kojim se zadaju rasponi, dani su u ovoj tabeli:

s2

String s2.

s2, pos2, len2

Najviše len2 znakova iz s2 polazeći od pos2.

cp

Znakovni niz na koji pokazuje cp, završen nul-znakom.

cp, len2

Najviše len2 znakova iz znakovnog niza na koji pokazuje cp.

n, c

n kopija znaka c.

b2, e2

Znakovi u rasponu određenom iteratorima b2 i e2.

Primjer:

string s3{'a','b','c'};  // s3 = "abc"
s3.append("defg",0,3);   // s3 = "abcdef"
s3.append(2, 'g');       // s3 = "abcdefgg"

vector<char> vec{'h','i','j'};
s3.append(vec.begin(), vec.end());   // s3 = "abcdefgghij"

s3.replace(0,6,"--");     // s3 = "--gghij"
auto s4 = s3.substr(5);   // s4 = "ij"
s3.replace(2,5,s4);       // s3 ="--ij"

find

Imamo šest verzija funkcija za pretraživanje stringa. Svaka od tih funkcija vraća string::size_type tip koji predstavlja indeks pozicije na kojoj je nađena tražena vrijednost. U slučaju negativnog rezultata pretrage vraća se string::npos vrijednost, koja garantirano nije dobra vrijednost indeksa.

Svaka od funkcija pretraživanja ima više preopterećenih varijanti koje se razlikuju po načinu na koji je zadano ono što se traži.

s.find(args)

Nađi prvo pojavljivanje args u s.

s.rfind(args)

Nađi zadnje pojavljivanje args u s.

s.find_first_of(args)

Nađi prvo pojavljivanje bilo kojeg znaka iz args u s.

s.find_last_of(args)

Nađi zadnje pojavljivanje bilo kojeg znaka iz args u s.

s.find_first_not_of(args)

Nađi prvi znak u s koji nije iz args .

s.find_last_not_of(args)

Nađi zadnji znak u s koji nije iz args .

Argument args koji se traži dan je ovoj tabeli:

c, pos

Traži znak c polazeći od pozicije pos u s. Defaultna vrijednost za pos je nula.

s2, pos

Traži string s2 polazeći od pozicije pos u s. Defaultna vrijednost za pos je nula.

cp, pos

Traži znakovni niz završen nul-znakom na koji pokazuje cp polazeći od pozicije pos u s. Defaultna vrijednost za pos je nula.

cp, pos, n

Traži prvih n znakova u znakovnom nizu na koji pokazuje cp polazeći od pozicije pos u s. Defaultna vrijednost za pos je nula.

Primjer:

string s5("Molim da ne koristite preopterećenje operatora i funkcija u svom programu.");
auto n = s5.find("preopterećenje");  // n = 22
n =s5.find("i", 22);                 // n = 48
n = s5.rfind("preopterećenje");      // n = 22
n = s5.find_first_of("kd");          // n=6, nalazi "d"
n = s5.find_first_not_of("Mmkdol");  // n=3, nalazi "i"
n = s5.find_last_not_of("Mmkdol");   // n=74, nalazi "."

compare

Za uspoređivanje stringova možemo koristiti operatore ==, !=, <, >, <= i >=. Svi oni vrše leksikografsko uspoređivanje, znak-po-znak. To znači da se uspoređuju odgovarajući znakovi u stringovima sve dok se ne naiđe na prvi par znakova koji su različiti. Usporedba je tada određena odnosnom ta dva znaka, čiji je pak poredak fiksiran abecedom. Mala slova prethode velikim slovima, a velika slova prethode brojevima. Ako je jedan string podstring drugog, onda je dulji string veći.

Pored operatora uspoređivanja string daje šest preopterećenih verzija funkcije compare koja vrši leksikografsko uspoređivanje. Rezultat tih funkcija je analogan rezultatu koji daje funkcija strcmp iz standardne biblioteke jezika C. Dakle,

s1.compare (args);

daje sljedeći rezultat:

  • Pozitivnu vrijednost ako je s1 veći od stringa kojeg reprezentira args;

  • Negativnu vrijednost ako je s1 manji od stringa kojeg reprezentira args;

  • Nulu ako je s1 jednak stringu kojeg reprezentira args.

Funkcije su dane ovdje:

s.compare(s2)

Uspoređuje s i s2.

s.compare(pos1, n1, s2)

Uspoređuje n1 znakova iz s, počevši od pozicije pos1, sa s2.

s.compare(pos1, n1, s2, pos2, n2)

Uspoređuje n1 znakova iz s, počevši od pozicije pos1, sa n2 znakova iz s2 počevši od pos2.

s.compare(cp)

Uspoređuje s i znakovni niz završen nul-znakom na koji pokazuje cp.

s.compare(pos1, n1, cp)

Uspoređuje n1 znakova iz s, počevši od pozicije pos1, sa znakovnim nizom završenim nul-znakom na koji pokazuje cp.

s.compare(pos1, n1, cp, n2)

Uspoređuje n1 znakova iz s, počevši od pozicije pos1, sa n2 znakova počevši od pozicije na koju pokazuje cp.