Rad sa stringovima
String je tekstualni tip podataka, koji suštinski predstavlja niz znakova. Rad sa stringovima je jedna od najvažnijih tema u programiranju - skoro da nema ozbiljnije aplikacije gde se ne zahteva obrada tekstualnog ulaza ili kreiranje rezultata u obliku teksta. Web aplikacije prenose podatke između klijenta i servera u tekstualnom obliku - bilo preko HTTP zahteva kada se klijent "obraća" serveru, bilo u HTML, XML ili JSON obliku kada server šalje podatke nazad.
Tipični problemi u obradi stringova predstavljaju pronalaženje i zamenu. Ovi zadaci prilično podsećaju na rad sa nizovima i to nije slučajno, pošto smo već rekli da stringovi predstavljaju nizove znakova. Tako i svaki znak u stringu ima svoj redni broj (kao indeks elementa niza). Inače, ovaj naziv "niz znakova" uopšte nije slučajan, pošto većina programskih jezika ima poseban tip char za pojedinačan znak.
Različiti programski jezici rade sa stringovima na različit način. Npr. u standardnom Pascalu i Delphiju/Lazarusu, prvi znak stringa je pod indeksom 1, dok se (bar za tzv. "kratke" stringove) u "nultom" bajtu nalazi dužina stringa. Sa druge strane u jezicima poput C-a, Jave, PHP-a ili JavaScripta, string počinje od nule (prvi znak ima indeks 0).
Indeks | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Znak | W | e | b | s | a | j | t |
Jezici poput C-a imaju tzv. stringove završene nulom (null-terminated strings), što znači da se u memoriji računara posle poslednjeg znaka nalazi bajt 0, kojim se označava kraj stringa.
Od uvođenja UNICODE/UTF8 kodnih strana, obrada stringova postaje kompleksnija pošto (za razliku od starih ASCII znakova), sada jedan znak u stringu ne mora biti predstavljen isključivo jednim bajtom.
Svi moderni programski jezici imaju veliki broj funkcija za rad sa stringovima. U tekstu koji se bavio tipovima podataka, pomenuli smo stringove kao tekstualni tip podataka.
U jeziku C++ je osim običnog string tipa uvedena i string klasa, a u Javi i JavaScriptu i ne postoji običan string tip, već su svi stringovi praktično objekti.
Operacije nad stringovima
Nad stringovima je moguće obaviti određene operacije. Pogledajmo koji operandi mogu da rade sa tekstualnim podacima.
Operatori koji rade sa stringovima | |
---|---|
S + F | rezultat je novi string koji nastaje povezivanjem stringova S i F. |
S == F | Vraća logičku vrednost TRUE ako je string S jednak stringu F. |
S != F | Vraća logičku vrednost TRUE ako je string S različit od stringa F. |
S < F | Vraća logičku vrednost TRUE ako je string S manji od stringa F. |
S > F | Vraća logičku vrednost TRUE ako je string S veći od stringa F. |
S <= F | Vraća logičku vrednost TRUE ako je string S manji ili jednak stringu F. |
S >= F | Vraća logičku vrednost TRUE ako je string S veći ili jednak stringu F. |
Konkatenacija stringova
Praktično jedina specifična operacija ovde je konkatenacija stringova. Ovaj, malo rogobatni termin, označava prosto dodavanje stringa na string. U većini programskih jezika postoji mogućnost povezivanja stringova i za to se najčešće koristi operator sabiranja (+). Ovo funkcioniše u Pascalu, C++, Javi, Python-u, JavaScriptu (a samim tim i u Viziji)...
"Web" + "sajt" ---> "Websajt"
Jezik PHP je izuzetak, pošto za konkatenaciju koristi specijalan operator tačku (.).
"Web" . "sajt" ---> "Websajt"
Ako ste imali iskustva u Excel-u, znate da on na svoj način dodaje string na string, pomoću operatora ampersend (&).
"Web" & "sajt" ---> "Websajt"
Jezik C nema ovakav operator, ali ima funkciju strcat(s1,s2) koja služi za povezivanje stringova.
Poređenje stringova
Ne bismo smeli da zaboravimo ni relacione operatore, odnosno operacije upoređivanja, koji takođe rade sa stringovima. To znači da dva stringa možemo upoređivati u smislu provere da li su jednaki, različiti, manji ili veći.
Stringovi se ne upoređuju po dužini (tj. broju znakova), već prema poziciji znakova stringa u kodnoj tabeli. Drugim rečima, u velikoj većini slučajeva, "manji" je onaj string koji bi po abecedi bio poređan ispred drugog stringa.
"Web" > "Abrakadabra" ---> TRUE
Ne zaboravite da programski jezici tumače velika i mala slova u stringovima kao različita - pošto se velika slova u kodnom rasporedu nalaze ispred malih, može se desiti da dobijete neočekivane rezultate upoređivanja.
"WEB" < "aca" ---> TRUE
Upoređivanje se vrši znak po znak. Znači, prvo se poredi prvi-sa-prvim, pa drugi-sa-drugim, dok se ne stigne do kraja stringa. Inače, tek ako su stringovi jednaki po znakovima, manji je onaj koji je kraći.
"prst" < "prsten" ---> TRUE
Funkcije za rad sa stringovima u Viziji
Rad sa stringovima u Viziji najviše podseća na rad u JavaScriptu. To znači da se string literali mogu pisati pod navodnicima ili apostrofima. Iako u se većini programskih jezika pravi razlika između znakovnog (char) i string tipa, kod nas postoje samo stringovi, a pojedinačan znak je samo string dužine 1.
Stringovi | |
---|---|
len(s) | Vraća dužinu zadatog stringa s. Ova dužina je broj znakova stringa |
getchar(s,n) | Vraća n-ti znak stringa s (prvi znak stringa je 0) |
str(x) | Zadati broj x konvertuje u string |
val(s) | Zadati string s konvertuje u broj (pod uslovom da je broj zadat u obliku stringa) |
ord(s) | Vraća numerički kod zadatog znaka s |
chr(x) | Vraća znak koji odgovara zadatom numeričkom kodu x |
Dužina stringa
Ovo je stvar bez koje nikako ne možemo. U svakom programskom jeziku koji radi sa stringovima postoji makar mogućnost da se u programu dođe do dužine stringa, izražene kao broj znakova. Za ovo koristimo funkciju len() koja za zadati string, kao rezultat vraća broj znakova.
len("Websajt") ---> 7
Zašto je dužina stringa toliko važna? Pa jednostavno, za svaki "prolazak" kroz znakove stringa potrebno je napraviti ciklus, a skoro uvek će on biti zadat od 0 (početka stringa) do dužine stringa (što predstavlja kraj stringa). Ne zaboravite da stringovi u Viziji (kao i u JavaScriptu) počinju od 0.
To znači, da ako je dužina stringa 10, znakovi su označeni indeksima od 0 do 9, znači poslednji znak je za jedan manji od dužine.
Izdvajanje znaka iz stringa
Druga jako važna funkcija je getchar(), koja iz zadatog stringa, vraća znak koji se nalazi na zadatoj poziciji. Ne zaboravite - pozicija prvog znaka je 0.
Kao prvi parametar se zadaje string, a drugi indeks.
getchar("Websajt",3) ---> "s"
getchar("Websajt",-3) ---> ""
getchar("Websajt",80) ---> ""
Ako se zada nepostoječi indeks, kao rezultat ćemo dobiti prazan string - dakle, neće biti prijavljena greška.
Primer prolaska kroz znakove stringa
Izdvajanje pojedinih znakova iz stringa je zadatak u kome moramo da koristimo petlju. Najpraktičnije je da to bude brojački ciklus, pošto jednom kad imamo string, tačno znamo koliko on ima znakova (pomoću funkcije len()), a to je tačno onoliko puta koliko treba da prođemo kroz ciklus.
Dakle, na počektu se unosi string S (to će u zadacima biti uobičajeno). Onda ulazimo u ciklus i u njemu postavljamo brojačku promenljivu i na početnu vrednost 0 (zato što string počinje od "nultog" znaka).
Ciklus se ponavlja sve dok je brojačka promenljiva i manja od dužine stringa, koju dobijamo zahvaljujući funkciji len(S).
Na kraju svake iteracije se i povećava za jedan.Unutar ciklusa izdvajamo i-ti znak stringa s, kao i-ti element niza S[i] i smeštamo ga u promenljivu znak. Posle tog koraka, sa tako izdvojenim znakom možemo raditi bilo šta.
Dakle ne zaboravite - u svakoj iteraciji ciklusa radimo sa po jednim znakom stringa.
Numerička konverzija
Konverzija stringa se odnosi na pretvaranje stringa u broj i obrnuto. Funkcija str() zadati broj pretvara u string.
str(14) ---> "14"
str(17.4) ---> "17.4"
str("tekst") ---> GREŠKA
Vizija će "umeti" da izvrši konverziju ako zadamo celi ili broj sa decimalama. Ako zadamo nenumeričku vrednost, izazvaćemo grešku u izvršavanju.
Funkcija val() radi suprotno od funkcije str(), odnosno zadati string pretvara u broj. Da bi funkcija ispravno radila, potrebno je da string koji se zadaje u stvari sadrži neki broj.
val("5") ---> 5
val(" -15.3 ") ---> -15.3
val(" 13. 4 ") ---> 13
val("4.1txt6") ---> 4.1
val("z4.1txt") ---> NaN
val(55) ---> GREŠKA
Za zadati string je bitno da počinje ciframa (ili minusom) - ako se posle cifara pojavljuju neki drugi znakovi, biće ignorisani.
Vodeći i završni razmaci se ignorišu, a ako unutar broja imamo razmake, računaće se samo cifre pre prvog takvog razmaka.
Ako zadati string počinje nekim drugim znakom, rezultat će biti vrednost NaN (Not a Number) koja je specifična za JavaScript. Ako ovu vrednost kasnije koristimo u drugim izrazima, svi će oni dobiti vrednost NaN, što je u Viziji praktično ekvivalent grešci.
Ako kao vrednost uopšte ne zadamo tekstualni podatak, Vizija će prijaviti grešku u izvršavanju.
Konverzija znakova
Kao što znamo, svaki tekstualni znak se u memoriji računara nalazi u obliku broja, o čemu smo pisali u lekciji o predstavljanju teksta. Postoji standard koji tačno kaže kom znaku odgovara koji broj. Ovaj standard se menjao tokom godina - jako dugo se koristio ASCII, a danas je u upotrebi UNICODE. Zahvaljujući tome kako su znakovi poređani u toj tabeli računar može da upoređuje stringove i sortira ih po abecedi. Broj je dodeljen bukvalno svakom znaku koji postoji na računaru - znak uzvika, zarez, tačka, svaka cifra, svako veliko i svako malo slovo, pa čak i razmak - svi imaju svoj "broj".
Vizija se automatski prilagođava standardu koji koristi JavaScript u vašem web čitaču. Najverovatnije će to biti dvobajtni UNICODE, tj. tabela sa 65536 mogućih znakova.
Da bismo došli do "koda" za neki znak, koristimo funkciju ord(), kojoj zadajemo znak u obliku stringa. Ova funkcija očekuje da to bude tačno jedan znak.
ord("A") ---> 65
ord("Bilja") ---> 66
ord(75) ---> GREŠKA
Ako zadamo string koji ima više znakova, gledaće se samo prvi znak. Ako se zada vrednost koja nije string, Vizija će javiti grešku.
Funkcija chr() za zadati redni broj kao rezultat vraća znak pod tim rednim brojem. Očekuje se celi broj, a ako se zada broj sa decimalama, gleda se samo celi deo broja. Ako zadamo negativan broj, Vizija će se nekako snaći uzimajući znakove s kraja tabele.
chr(65) ---> "A"
chr(66.9) ---> "B" isto kao chr(66)
chr(-100) ---> "ワ" isto kao chr(65436)
chr("70") ---> GREŠKA
Ako zadamo neku nenumeričku vrednost, izazvaćemo grešku.