RAD SA TEKSTUALNIM PODACIMA – STRINGOVI
Sadržaj lekcije: Stringovi u C++
Dobrodošli na lekciju posvećenu stringovima (niskama) u jeziku C++! U ovoj lekciji naučićete šta su stringovi, kako se koriste i koje su njihove prednosti u odnosu na tradicionalne pristupe radu sa tekstom.
Obradićemo osnovne koncepte, rad sa tipom char, razliku između C-stil stringova i modernog std::string, kao i najčešće operacije nad tekstom. Takođe ćemo obuhvatiti naprednije tehnike kao što su pretraga, izdvajanje podniski i obrada teksta.
Šta ćete naučiti
Uvod u stringove u C++
Stringovi (niske) u C++ predstavljaju sekvence karaktera koje se koriste za čuvanje i obradu tekstualnih podataka.
Postoje dva osnovna pristupa radu sa stringovima:
-
C-stil stringovi: nizovi karaktera koji se završavaju nul-terminatorom (
'\0'). Oni zahtevaju ručno upravljanje memorijom i podložni su greškama (npr. prekoračenje bafera). -
C++ string (std::string): klasa iz standardne biblioteke (
<string>) koja omogućava sigurniji i jednostavniji rad sa tekstom. Automatski upravlja memorijom i nudi veliki broj korisnih funkcija.
Preporuka: U modernom C++ programiranju gotovo uvek koristite std::string umesto C-stil stringova.
U ovoj lekciji ćete naučiti kako da:
- kreirate i menjate stringove
- čitati tekst sa ulaza
- pretražujete i izdvajate delove stringa
- obrađujete tekst karakter po karakter
Podaci tipa char u C++
Tip podataka char služi za čuvanje jednog karaktera. Interno, karakter se zapravo predstavlja kao broj (najčešće ASCII kod).
Drugim rečima, char je celobrojni tip koji zauzima 8 bita memorije i koristi se za skladištenje kodova karaktera.
Važno: Karakter nije samo simbol — on u pozadini ima svoju numeričku vrednost.
Osnovni primer
#include <cstdio>
int main() {
char c = 'A';
printf("%d, %c\n", c, c);
return 0;
}
Na izlazu će se prikazati: 65, A
Prvo se ispisuje broj (ASCII kod), a zatim sam karakter.
- %d → ispisuje broj
- %c → ispisuje karakter
ASCII tabela – primer
#include <cstdio>
int main() {
for(char c = 'A'; c <= 'Z'; c++) {
printf("%c = %d\n", c, c);
}
return 0;
}
Ovaj program ispisuje velika slova i njihove ASCII kodove.
Vežba: Izmenite opseg da ispišete:
- mala slova (
'a' - 'z') - cifre (
'0' - '9')
Specijalni (escape) karakteri
#include <iostream>
using namespace std;
int main() {
char a = '\''; // apostrof
char n = '\n'; // novi red
char t = '\t'; // tab
cout << "Apostrof: " << a << endl;
cout << "Test novog reda:" << n << "Novi red" << endl;
cout << "Tab test:" << t << "tekst" << endl;
return 0;
}
Escape karakteri kao \n i \t su veoma korisni za formatiranje ispisa teksta.
C-stil stringovi (niz karaktera)
C-stil stringovi potiču iz jezika C i predstavljaju niz karaktera koji se završava
specijalnim nul karakterom '\0'.
Primer:
char text[8] = {'P','o','z','d','r','a','v','\0'};
Ili jednostavnije:
char text[] = "Pozdrav";
Ovaj način rada zahteva ručno upravljanje memorijom i može dovesti do grešaka (npr. prekoračenje bafera), zbog čega se u modernom C++-u ređe koristi.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|
| P | o | z | d | r | a | v | \0 |
Tekstualni podaci u C++
U jeziku C++ postoji tip podataka string koji služi za rad sa tekstom. Koristi se kao i svi ostali tipovi podataka, a promenljiva tipa string deklariše se na sledeći način.
Zapravo, string predstavlja objekat klase std::string iz standardne biblioteke.
using namespace std;
string s = "Ovo je neki tekst.";
// ili eksplicitno:
std::string s = "Ovo je neki tekst.";
Unos stringova
Postoje dva osnovna načina za unos stringova:
1. Korišćenje operatora cin
string ime;
cin >> ime;
Ovaj način učitava samo jednu reč (prekida se na razmaku).
2. Korišćenje funkcije getline
string ime;
getline(cin, ime);
Ova funkcija učitava ceo red teksta (uključujući razmake).
Problem sa kombinovanjem cin i getline
int broj;
cin >> broj;
cin.ignore(); // uklanja preostali newline
string tekst;
getline(cin, tekst);
Bez cin.ignore(), getline može preskočiti unos.
Unos kompletnog reda teksta
string text;
getline(cin, text);
Funkcija getline čita ceo red teksta sve dok korisnik ne pritisne Enter.
- Prvi argument je cin – izvor podataka
- Drugi argument je promenljiva u koju se smešta tekst
Ova funkcija je posebno korisna kada tekst sadrži razmake.
Funkcija getline nalazi se u zaglavlju:
#include <string>
Razdvajanje reči iz teksta
Ako koristimo varijantu funkcije getline() sa trećim parametrom (delimiterom), možemo izdvojiti reči iz teksta.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
string text;
string rec;
int n = 0;
getline(cin, text);
stringstream T(text);
while(getline(T, rec, ' ')) {
cout << rec << endl;
n++;
}
cout << "U tekstu ima " << n << " reci" << endl;
return 0;
}
U ovom primeru tekst se prvo učitava u promenljivu text, a zatim se prebacuje u stringstream.
Nakon toga, pomoću petlje izdvajamo reči jednu po jednu koristeći razmak kao delimiter.
Direktno sa standardnog ulaza
#include <iostream>
#include <string>
using namespace std;
int main() {
string rec;
int n = 0;
while(getline(cin, rec, ' ')) {
cout << rec << endl;
n++;
}
cout << "U tekstu ima " << n << " reci" << endl;
return 0;
}
Testirajte svoj kod u editoru ispod!
Osnovne operacije sa stringovima
Dodela stringa
Možemo dodeliti vrednost jednog stringa drugom.
string str1 = "Zdravo!";
string str2;
str2 = str1; // kopiranje sadržaja stringa
Takođe, string možemo inicijalizovati drugim stringom:
string str1 = "Zdravo!";
string str2 = str1; // inicijalizacija prilikom deklaracije
Dodela kod
std::string pravi kopiju sadržaja (deep copy),
što znači da promena jednog stringa ne utiče na drugi.
Ako želiš da izbegneš kopiranje (zbog performansi), koristi reference:
string& ref = str1;
Spajanje (konkatenacija) stringova
Dva ili više stringova mogu se spojiti pomoću operatora +.
#include <iostream>
#include <string>
using namespace std;
int main() {
string punoIme;
string ime = "Nenad";
string prezime = "Milenković";
punoIme = ime + " " + prezime; // konkatenacija
cout << punoIme << endl;
return 0;
}
Operator
+ kreira novi string.
Za veliki broj spajanja, efikasnije je koristiti append().
Dužina stringa
Za određivanje dužine stringa koristi se funkcija length() ili size().
string str1 = "Primer";
cout << str1.length(); // ispis: 6
Primer programa:
#include <iostream>
#include <string>
using namespace std;
int main() {
string nazivGrada;
cout << "Unesi naziv grada: ";
getline(cin, nazivGrada); // unos sa razmacima
int duzina = nazivGrada.length(); // broj karaktera
cout << "Grad: " << nazivGrada << endl;
cout << "Naziv sadrži " << duzina << " karaktera." << endl;
return 0;
}
Funkcija
length() već vraća tačan broj karaktera —
nije potrebno oduzimati 1.
length() i size() rade isto — možeš koristiti bilo koju.
Poređenje stringova
Stringovi se porede pomoću operatora: ==, !=, <, >, <=, >=.
Poređenje je leksikografsko (po abecedi), a ne po dužini.
bool b;
b = ("abak" == "abak"); // true
b = ("Ab" < "AA"); // false (velika/mala slova imaju različite ASCII vrednosti)
Velika i mala slova se razlikuju ('A' != 'a'), jer imaju različite ASCII vrednosti.
Primer: Provera lozinke
#include <iostream>
#include <string>
using namespace std;
int main() {
string lozinka;
cin >> lozinka;
if (lozinka == "@n0nimus_@n0nimus") {
cout << "Tačna lozinka" << endl;
} else {
cout << "Netačna lozinka" << endl;
}
return 0;
}
Za poređenje bez obzira na velika/mala slova, prvo konvertuj string u isti oblik (npr. sve u mala slova).
Ispitivanje znakova pomoću funkcija iz zaglavlja <cctype>
Pri radu sa karakterima u programskom jeziku C++, često je potrebno proveriti da li je dati znak slovo, cifra, razmak ili neki drugi tip karaktera. Umesto pisanja složenih uslova sa više logičkih izraza, možemo koristiti gotove funkcije iz zaglavlja <cctype>, koje značajno pojednostavljuju rad sa znakovima.
- Čitljiviji i kraći kod
- Manje grešaka u logici
- Standardizovane i optimizovane funkcije
Ove funkcije omogućavaju:
- proveru da li je karakter slovo (isalpha)
- proveru da li je karakter cifra (isdigit)
- razlikovanje malih i velikih slova (islower, isupper)
- proveru belih znakova (isspace)
- konverziju između malih i velikih slova (tolower, toupper)
Korišćenjem ovih funkcija kod postaje čitljiviji i efikasniji, što je posebno korisno u obradi teksta, validaciji unosa i parsiranju podataka.
Najčešće funkcije iz <cctype>
- isalnum(ch) – da li je ch slovo ili cifra?
- isalpha(ch) – da li je ch slovo?
- islower(ch) – da li je ch malo slovo?
- isupper(ch) – da li je ch veliko slovo?
- isdigit(ch) – da li je ch cifra?
- isspace(ch) – da li je ch beli znak (razmak, tab, novi red)?
- ispunct(ch) – da li je ch znak interpunkcije?
- iscntrl(ch) – da li je ch upravljački znak?
- tolower(ch) – pretvara veliko slovo u malo
- toupper(ch) – pretvara malo slovo u veliko
Sve funkcije vraćaju vrednost različitu od nule (true) ili 0 (false).
Primer upotrebe
Zadatak:
Napisati program koji omogućava unos jednog karaktera, a zatim ispituje i ispisuje njegove osobine korišćenjem funkcija iz zaglavlja <cctype>.
- da li je slovo ili cifra
- da li je slovo
- da li je cifra
- da li je malo slovo (i prikazati veliko)
- da li je veliko slovo (i prikazati malo)
- da li je beli znak
- da li je znak interpunkcije
- da li je upravljački znak
#include <iostream>
#include <cctype>
using namespace std;
int main() {
char ch;
cout << "Unesite karakter: ";
cin >> ch;
// Slovo ili cifra
if (isalnum(ch)) {
cout << ch << " je slovo ili cifra.\n";
}
// Slovo
if (isalpha(ch)) {
cout << ch << " je slovo.\n";
}
// Cifra
if (isdigit(ch)) {
cout << ch << " je cifra.\n";
}
// Malo slovo
if (islower(ch)) {
cout << ch << " je malo slovo.\n";
cout << "Veliko slovo: " << (char)toupper(ch) << '\n'; // konverzija u veliko
}
// Veliko slovo
if (isupper(ch)) {
cout << ch << " je veliko slovo.\n";
cout << "Malo slovo: " << (char)tolower(ch) << '\n'; // konverzija u malo
}
// Beli znak
if (isspace(ch)) {
cout << "Uneti karakter je beli znak.\n";
}
// Interpunkcija
if (ispunct(ch)) {
cout << ch << " je znak interpunkcije.\n";
}
// Upravljački znak
if (iscntrl(ch)) {
cout << "Uneti karakter je upravljački znak.\n";
}
return 0;
}
Kako program radi
- Svaka funkcija proverava jednu osobinu karaktera
- Više uslova može biti tačno istovremeno
- Na primer: 'A' je i isalpha i isupper
Ove funkcije se zasnivaju na ASCII kodovima, pa njihovo ponašanje zavisi od kodne strane (encoding-a).
Isprobaj unos sledećih karaktera i posmatraj rezultat:
- 'A'
- 'a'
- '5'
- ' '
- '!'
- '\n' (novi red)
Vizuelni prikaz indeksa u stringu
Indeksi u stringu počinju od 0. Sledeći primer pokazuje kako su karakteri raspoređeni:
Tekst: P o z d r a v Indeks: 0 1 2 3 4 5 6
Na primer:
- text[0] → 'P'
- text[3] → 'd'
- text.substr(2,3) → "zdr"
Razumevanje indeksa je ključno za pravilno korišćenje funkcija kao što su find(), substr() i erase().
Pristup pojedinačnim karakterima stringa
String se sastoji od pojedinačnih karaktera kojima možemo pristupiti pomoću indeksa.
Indeksi u stringu počinju od 0.
Prvi karakter ima indeks 0, drugi indeks 1 itd.
Pristup pomoću indeksa
#include <iostream>
#include <string>
using namespace std;
int main() {
string tekst = "Programiranje";
cout << tekst[0] << endl; // P
cout << tekst[1] << endl; // r
cout << tekst[2] << endl; // o
return 0;
}
Karakter na određenoj poziciji dobija se pomoću uglastih zagrada.
Prolazak kroz ceo string
#include <iostream>
#include <string>
using namespace std;
int main() {
string tekst = "Robot";
for(size_t i = 0; i < tekst.length(); i++)
{
cout << tekst[i] << endl;
}
return 0;
}
U svakoj iteraciji petlje pristupa se sledećem karakteru stringa.
Moderniji način (range-based for petlja)
#include <iostream>
#include <string>
using namespace std;
int main() {
string tekst = "AI";
for(char c : tekst)
{
cout << c << endl;
}
return 0;
}
Range-based for petlja je jednostavnija kada ti indeks karaktera nije potreban.
Funkcije za pretragu unutar stringa
Za pretragu pozicije karaktera ili dela teksta unutar stringa koristi se funkcija find().
Funkcija find() vraća indeks (poziciju) prvog pojavljivanja podstringa.
Ako podstring nije pronađen, vraća string::npos.
Primer pronalaženja podstringa "je":
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "Ovo je primer teksta gde se rec je pojavljuje vise puta.";
// Prvo pojavljivanje
size_t pozicija = str1.find("je");
// Sledeće pojavljivanje (počevši od pozicije 10)
size_t pozicija2 = str1.find("je", 10);
// Poslednje pojavljivanje (pretraga unazad)
size_t pozicija3 = str1.rfind("je");
cout << "Prvo: " << pozicija << endl;
cout << "Sledece: " << pozicija2 << endl;
cout << "Poslednje: " << pozicija3 << endl;
return 0;
}
Koristi tip size_t za pozicije (umesto int) jer je to standardni tip koji funkcija find() vraća.
Ako traženi tekst ne postoji, funkcija vraća string::npos.
Tip za pozicije je size_t (bez znakova), a ne int.
Funkcija rfind() radi isto kao find(), ali pretražuje string unazad (od kraja ka početku).
Pokušaj:
- da pronađeš reč koja ne postoji u stringu
- ispiši rezultat i proveri da li je jednak string::npos
Podstringovi
Za izdvajanje dela stringa koristi se funkcija substr() iz biblioteke <string>.
substr(početak, dužina)
Primer 1
#include <iostream>
#include <string>
using namespace std;
int main() {
string text = "Posmatrano u hipersvemiru";
// Uzima 11 karaktera počevši od pozicije 3
string deoTeksta = text.substr(3, 11);
cout << deoTeksta << endl; // "matrano u h"
return 0;
}
Originalni string ostaje nepromenjen. Indeksi počinju od 0.
Bez drugog parametra
string text = "galaksije predstavljaju";
string podstring = text.substr(4); // od pozicije 4 do kraja
Ako izostaviš drugi parametar, uzima se tekst od zadate pozicije do kraja stringa.
Granični slučajevi
string text = "012345";
// Ispravno
string fragment1 = text.substr(2, 3); // "234"
// Neispravno – početna pozicija van opsega
// string fragment2 = text.substr(6, 2); // baca izuzetak out_of_range
// Prevelika dužina – dozvoljeno
string fragment3 = text.substr(3, 10); // "345"
Ako je početna pozicija van opsega → program može baciti grešku.
Ako je dužina prevelika → uzima se sve do kraja stringa.
Brisanje i izmena podstringova
Za uklanjanje dela stringa koristi se funkcija erase().
erase(početna_pozicija, broj_karaktera)
#include <iostream>
#include <string>
using namespace std;
int main() {
string text = "Ovo je test";
// Briše prvih 7 karaktera ("Ovo je ")
text.erase(0, 7);
cout << text << endl; // "test"
return 0;
}
Nakon izvršavanja, string postaje "test".
Funkcija erase() menja originalni string (nije kopija!).
Zamena dela stringa
Umesto brisanja, deo stringa možemo zameniti pomoću funkcije replace().
#include <iostream>
#include <string>
using namespace std;
int main() {
string text = "Ovo je test";
// Menja "je" sa "nije"
text.replace(4, 2, "nije");
cout << text << endl; // "Ovo nije test"
return 0;
}
Dužina novog teksta ne mora biti ista kao dužina starog.
Podela stringa pomoću separatora ","
Zadatak: Razdvojiti tekst na dva dela koristeći zarez kao separator.
Masarikova 18, Beograd
Očekivan izlaz:
Masarikova 18 Beograd
Rešenje korak po korak
- učitati ceo red (getline)
- pronaći poziciju zareza (find())
- izdvojiti delove (substr())
#include <iostream>
#include <string>
using namespace std;
int main() {
string redTeksta;
string leviDeo, desniDeo;
cout << "Unesi red teksta: ";
getline(cin, redTeksta);
// Pronalazi poziciju zareza
size_t sepInd = redTeksta.find(',');
// Provera da li postoji zarez
if (sepInd != string::npos) {
// Leva strana (pre zareza)
leviDeo = redTeksta.substr(0, sepInd);
// Desna strana (posle zareza)
desniDeo = redTeksta.substr(sepInd + 1);
cout << leviDeo << endl;
cout << desniDeo << endl;
} else {
cout << "Zarez nije pronađen!" << endl;
}
return 0;
}
Koristi find() umesto find_first_of() kada tražiš tačno jedan znak ili tekst.
Ako separator ne postoji, find() vraća string::npos.
Korisne pomoćne funkcije za rad sa stringovima
U praksi često imamo potrebu za dodatnim operacijama koje nisu direktno deo std::string interfejsa, kao što su:
- razdvajanje stringa (split)
- uklanjanje razmaka (trim)
Ove funkcije ne postoje direktno u standardnoj biblioteci kao gotove funkcije, ali ih lako možemo implementirati sami.
Split funkcija (razdvajanje stringa)
Split razdvaja string na više delova na osnovu separatora.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> split(const string& s, char delimiter) {
vector<string> rezultat;
size_t start = 0;
size_t end;
while ((end = s.find(delimiter, start)) != string::npos) {
rezultat.push_back(s.substr(start, end - start));
start = end + 1;
}
rezultat.push_back(s.substr(start)); // poslednji deo
return rezultat;
}
int main() {
string tekst = "Ana,Marko,Jovan";
vector<string> delovi = split(tekst, ',');
for (string x : delovi) {
cout << x << endl;
}
return 0;
}
Ova funkcija ne menja originalni string – vraća novi niz stringova (
vector).
Trim funkcija (uklanjanje razmaka)
Trim uklanja razmake sa početka i kraja stringa.
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
string trim(const string& s) {
size_t start = 0;
size_t end = s.length();
// uklanjanje razmaka sa početka
while (start < end && isspace(s[start])) {
start++;
}
// uklanjanje razmaka sa kraja
while (end > start && isspace(s[end - 1])) {
end--;
}
return s.substr(start, end - start);
}
int main() {
string tekst = " C++ je super! ";
string rezultat = trim(tekst);
cout << "[" << rezultat << "]" << endl;
return 0;
}
Funkcija isspace() uklanja sve bele znakove: razmak, tab, novi red itd.
Napredne operacije sa std::string u C++
Klasa std::string nudi brojne metode za fleksibilnu manipulaciju tekstom. Ove tehnike su posebno korisne u obradi podataka, parsiranju i radu sa korisničkim unosom.
- omogućavaju efikasniju obradu teksta
- smanjuju potrebu za ručnim radom sa karakterima
- čine kod čitljivijim i modularnijim
Konkatenacija stringova
Spajanje stringova može se izvršiti operatorom + ili metodom append().
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1 = "Pozdrav, ";
string s2 = "svete!";
string rezultat = s1 + s2; // operator +
s1.append(s2); // alternativno: menja s1
cout << rezultat << endl; // "Pozdrav, svete!"
cout << s1 << endl; // "Pozdrav, svete!"
return 0;
}
Operator + pravi novi string, dok append() menja postojeći.
Umetanje podstringova
Metoda insert() omogućava ubacivanje teksta na proizvoljnu poziciju.
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Dobro došli!";
s.insert(6, "svet "); // ubacuje tekst na indeks 6
cout << s; // "Dobro svet došli!"
return 0;
}
Pozicija mora biti validna – u suprotnom dolazi do greške (
out_of_range).
Promena veličine slova
Kombinacijom transform() i funkcija iz <cctype> možemo menjati slova.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
int main() {
string s = "Dobrodosli u C++";
// pretvaranje u velika slova
transform(s.begin(), s.end(), s.begin(), ::toupper);
cout << s << endl; // "DOBRODOSLI U C++"
return 0;
}
Za mala slova koristi ::tolower.
Funkcije
toupper i tolower rade na ASCII znakovima – ponašanje može zavisiti od enkodiranja.
Tokenizacija stringa
String se može podeliti na delove koristeći kombinaciju find() i substr().
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Marko,Ana,Petar,Jovana";
size_t pos;
string token;
while ((pos = s.find(',')) != string::npos) {
token = s.substr(0, pos); // uzimamo deo pre zareza
cout << token << endl;
s.erase(0, pos + 1); // uklanjamo obrađeni deo
}
cout << s << endl; // poslednji element
return 0;
}
• pronalazi separator
• izdvaja deo stringa
• briše obrađeni deo
• ponavlja dok ima separatora
|
Prethodno
|< Dvodimenzioni dinamički nizovi u c++ |
Sledeće
Pokazivači u C++ >| |
Srodni članci
Nizovi-primeri
Petlje u programskom jeziku JAVA
Sortiranje nizova
Operatori u C/C++ jeziku