Uvod
Šablonske niske u programskom jeziku Javscript (eng. - template literals), predstavljaju elegantan način da se u niske uvrste vrednosti promenljivih i izrazi, pre nego što niska bude prosleđena na dalju obradu, bez potrebe za upotrebom funkcija ili operatora za konkatenaciju.
U drugim programskim jezicima naziv 'šablonske niske' se ne koristi zvanično, ali, principi i tehnike svakako postoje, pa ćemo se detaljno osvrnuti na implementaciju, ne samo u JavaScript-u, već i u PHP-u, Python-u i C#-u.
Iako su šablonske niske glavna tema članka (kojoj ćemo posvetiti najviše pažnje), iskoristićemo priliku da se prethodno detaljno upoznamo i sa osnovnim načinima spajanja niski preko funkcija i operatora konketenacije.
Konkatenacija - osnovni metod spajanja niski i izraza
U većini programskih jezika, kada se funkciji za ispis preda jedan argument, odnosno promenljiva bilo kog tipa (makar kada su u pitanju prosti tipovi i niske), vrednost će biti uredno ispisana.
Primera radi, ako pozovemo console.log()
u JavaScript-u ....
let a = 124;
console.log(a);
.... ili funkciju print()
u Python-u ....
a = 124
print(a)
.... brojčani argument 124
će automatski biti pretvoren u nisku i dobićemo ispis "124"
.
Međutim, ako pokušamo da dodamo string konstantu kojom se promenljiva imenuje u ispisu, tako da ispis bude "a = 124"
....
let a = 124
console.log("a = " + a);
.... JavaScript će i ovoga puta uredno ispisati vrednost (recimo da program 'prepoznaje šta pokušavamo') ....
a = 124
.... ali će zato Python ....
a = 124
print("a = " + a)
.... prijaviti grešku:
Traceback (most recent call last):
File "ispis.py", line 5, in <module>
print("a = " + a)
TypeError: must be str, not int
Ništa strašno, ali, osim u slučaju JavaScript-a, funkcije i operatori za ispis niski u programskim jezicima postupaju onako kako smo videli na primeru Python-a: u kombinovanom ispisu u kome se pozivaju brojčane promenljive, moramo koristiti funkcije za pretvaranje brojčanih vrednosti u niske (naravno, dok se ne upoznamo sa šablonskim niskama).
Osvrnimo se ukratko na razloge .....
Razlike između formata zapisa brojčanih vrednosti i niski
Za primer ćemo uzeti int promenljive i niske.
Celobrojne vrednosti se na računarima zapisuju preko 4 bajta (32 bita) kojima se mogu predstaviti vrednosti između -2147483648
i 2147483647
.
Recimo, broj 143 u binarnom obliku ima sledeći oblik:

Niska "143", iako naizgled slična, predstavlja se na dosta drugačiji način, kao niska znakova "1", "4" i "3", shodno njihovim ASCII vrednostima:
- '1' - 49
- '4' - 52
- '3' - 51

Vidimo dakle da se vrednost 143 mora pretvoriti u nisku "143" i samo je pitanje da li će program to uraditi bez naše intervencije (JavaScript), ili neće (ostali).
Konkatenacija preko funkcija
Pre nego što se posvetimo operatorima konkatenacije, spomenućemo (informativno) da u programskim jezicima postoje i funkcije za spajanje niski.
Primera radi, sledeći JavaScript kod ....
var s1 = "Dobar ";
var s2 = "dan!";
console.log(s1.concat(s2));
.... u konzoli browser-a ispisaće "Dobar dan!".
Međutim, na ovakav pristup se nećemo osvrtati previše, jer ćemo uglavnom koristi operatore za spajanje niski i šablonske niske.
Upotrebu navedenih operatora i obrazaca za formatiranje teksta proučavaćemo na primeru sledećih jezika:
- JavaScript - opšteprisutni jezik za izradu web stranica
- C# - predstavnik C-olikih jezika
- Python - predstavnik skriptnih jezika
- PHP - predstavnik serverskih jezika
U osnovnom smislu, operator spajanja niski podrazumeva da su operandi koji mu se predaju na obradu niske, a, ukoliko određeni operand nije niska, mora se prethodno pretvoriti u nisku na način koji je za to predviđen u datom jeziku (osim u slučaju JS-a koji to radi automatksi, kao što smo već videli).
Konkatenacija preko operatora u JavaScript-u
Spajanje niski u JavaScript-u obavlja se preko operatora +
:
let s1 = "Vrednost ";
let s2 = "promenljive a je: ";
let a = 12;
let s = s1 + s2 + a;
Vidimo da je JavaScript (a to smo već i ranije naveli) izuzetak od pravila (koje u programskim jezicima obično važi), da se pri spajanju niski i vrednosti promenljivih, vrednost promenljive mora eksplicitno pretvoriti u nisku, preko zasebnih metoda ili na drugi propisan način, ali - JavaScript je jednostavno takav. :)
Na internetu se može pronaći mnogo pošalica na račun ove osobine JS-a ("2 + 2 = 22" i tome slično), ali, u praktičnom smislu, takav "liberalan" pristup za spajanje niski i vrednosti promenljivih uglavnom doprinosi lakšem i bržem kreiranju skripti.
Naravno, postoje i brojne situacije gde se mora voditi računa o tome da "2 + 2 ipak bude 4", pa ćemo tada koristiti funckije parseInt()
i parseFloat()
(pre nego što pozovemo operator +
) da JS-u nedvosmisleno stavimo do znanja da su u pitanju brojevi, a ne niske.
Formatiranje decimalnih vrednosti u JavaScript-u
Ukoliko je u ispisu potrebno formatirati decimalne vrednosti na određen način (zadati određen broja decimala), koristićemo funkciju toFixed(n)
(gde je n broj decimala):
var a = 12.3456;
console.log("a = " + parseFloat().toFixed(2));
Konkatenacija u Python-u
U python-u spajanje niski sa vredostima promenljivih metodom konkatenacije, podrazumeva upotrebu funckije str()
, koja za predatu brojčanu vrednost vraća odgovarajuću nisku, a sam operator spajanja je i ovde +
:
s1 = "Vrednost "
s2 = "promenljive a je: "
a = 12
s = s1 + s2 + str(a);
Formatiranje decimalnih vrednosti u Python-u
Python, za formatiranje ispisa decimalnih brojeva, nudi C-ovski pristup koji podrazumeva upotrebu specifikatora konverzije ....
a = 12.3456
print("a = %.2f" %a)
.... ali (shodno tome da je ovo ipak Python) nema zareza između komandnog stringa i realnih argumenata.
Konkatenacija u C#-u
U programskom jeziku C# u kome su brojčani podaci tipa Int32
i Float / Double
zapravo objekti klasa, za spajanje vrednosti promenljivih sa niskama, koristićemo ugrađenu metodu ToString()
:
String s1 = "Vrednost ";
String s2 = "promenljive a je: ";
Int32 a = 12;
String s = s1 + s2 + a.ToString();
Formatiranje decimalnih vrednosti u C#-u
Zadavanje formata decimalnih brojeva u C#-u je izvedeno na posebno elegantan način:
String s = "PI = " + Math.PI.ToString("0.0000");
U ovom slučaju, odredili smo četiri decimale za ispis a, ako želimo vodeće nule u ispisu, predaćemo nisku "00.0000"
kao argument pri pozivu metode ToString()
.
Konkatenacija u PHP - u
Spajanje niski u PHP-u (kako je to bio slučaj i sa drugim web jezikom, JavaScript-om) takođe je pojednostavljeno, ali, specifičnost je operator .
(tačka), umesto uobičajenog operatora +
:
<?php
$s1 = "Vrednost ";
$s2 = "promenljive a je: ";
$a = 12;
$s = $s1 . $s2 . $a;
?>
Formatiranje decimalnih vrednosti u PHP-u
Formatiranje decimalnih brojeva u PHP-u može se obaviti na nekoliko načina, a mi ćemo koristiti funkciju number_format()
:
<?php
$PI = 3.14159265359;
$s = "PI = " + number_format($PI, 4);
?>
Prepoznavanje praktičnih nedostataka operatora konkatenacije u slučaju većih niski
Ono što ste mogli pročitati do sada, ne bi vas baš skroz moglo ubediti da postoji išta sporno u tome da za spajanje niski (sa drugim niskama, ili vrednostima promenljivih / izraza) koristimo i dalje operatore konkatenacije, ali - to je zato što su primeri bili krajnje jednostavni.
Da bismo videli šta se dešava kada se niske zakomplikuju, pogledaćemo primer koji prikazuje jedan od svakodnevnih poslova u PHP-u - formatiranje HTML tagova koji koriste tekstualne sadržaje preuzete iz baze.
Za jednostavne kodove ....
<?php
$naslov_h1 = "<h1>" . $red['naslov_h1'] . "</h1>";
?>
.... svakako (i dalje) možemo koristiti operator konkatenacije.
Ako malo proširimo i dopunimo kod, po ideji sa prethodne slike (ali, nećemo ni ovde preterivati, zarad preglednosti), situacija će se promeniti.
U drugom primeru, HTML kod po sledećem obrascu ....
<?php
echo "<figure>
<img href='slike/galerija/mona_liza.png' alt='Leonardo DaVinči - Mona Liza Đokonda'/>
<figcaption>
Slika 12. - Mona Liza Đokonda, čuvena slika Leonarda DaVinčija, naslikana je #### godine i nalazi se u muzeju Luvr u Parizu
</figcaption>
</figcaption>";
?>
.... treba formatirati preko PHP-a (sa vrednostima preuzetim iz baze) ....
<?php
echo "<figure>
<img href='" . $red['datoteka_naziv'] . " alt='" . $red['slika_alt'] . "'/>
<figcaption>
" . $red['slika_opis'] .
"</figcaption>
</figcaption>";
?>
.... i već vidimo da konkatenacija nije ni iz daleka najelegantniji način.
Rešenje je (pogađate) upotreba šablonskih niski.
Definicija šablonskih niski u programskim jezicima
U najprostijem smislu šablonske niske su tekstualni obrasci zapisani na poseban način (vrlo slično običnim niskama, ali, ima razlika), tako da pojava identifikatora promenljivih, ili izraza, sugeriše interpretatorima / prevodiocima da ove delove u ispisu ne treba prikazivati doslovno, već ih treba zameniti odgovarajućim vrednostima.
Prosto rečeno - u pitanju je umetanje vrednosti promenljivih (ili drugih niski) u nisku.
Za početak, pogledaćemo implementaciju koncepta šablonskih niski u JavaScript-u, jedinom jeziku u kome se navedeni termin (eng. string literals - šablonske niske) upotrebljava kao zvaničan naziv.
Šablonske niske u JavaScript-u:
Da bismo se najlakše upoznali sa šablonskim niskama u JS-u, poslužićemo se praktičnim primerom:
Recimo da je preko AJAX-a (uskoro ćemo AJAX-u posvetiti zaseban članak), do JS skripte došao sledeći JSON objekat ....
let slika_info = {
"datoteka_naziv" : "slike/galerija/mona_liza.png",
"slika_alt" : "Leonardo Da Vinči - Mona Liza Đokonda",
"opis" : "Mona Liza Đokonda, čuvena slika Leonarda DaVinčija, nastala u periodu između 1503. i 1506, nalazi se u muzeju Luvr u Parizu i smatra se jednim od najvažnijih umetničkih dela svih vremena"
};
.... i da je potrebno formatirati HTML tag koji sadrži navedene podatke (koji smo videli u prethodnom odeljku).
Najlakše ćemo problem rešiti ako implementiramo funkciju koja preko šablonske niske vraća traženi HTML kod.
function slikaInfoFormatiranje(slika_info){
let sablon_slika =
`<figure>
<img href='${slika_info['datoteka_naziv']}' alt='${slika_info['slika_alt']}'/>
<figcaption>
${slika_info['opis']}
</figcaption>
</figcaption>`;
return sablon_slika;
}
Da pojasnimo:
- Šablonske niske u JS-u počinju i završavaju se znakom backtick
`
(nije apostrof, već znak koji se na tastaturama tipično nalazi ispod tastera ESC) - Vrednosti izraza (u našem slučaju koristili smo obične promenljive, a ne višečlane izraze), smeštaju se unutar vitičastih zagrada kojima direktno prethodi znak $
- Vrednosti na koje se pozivamo unutar šablonskih niski moraju biti unapred definisane (deklarisane i inicijalizovane)
Poslednja stavka zaslužuje posebnu pažnju (iako smo naveli pravilan postupak, objasnićemo i zašto je kod napisan tako kako jeste).
Šablon koji navodimo nije apstraktni šablon opšteg tipa koji se definiše na određenom mestu i može se proizvoljno pozvati i pre nego što smo inicijalizovali vrednosti koje se koriste u šablonskoj niski (kao što recimo funkcije možemo zapisivati pre i posle mesta na kojima ih pozivamo), već se pravi sadržaj niske koja je definisana preko šablona formira na licu mesta, shodno unapred definisanim vrednostima.
Ali, krajnje funkcionalno (i pri tom, sasvim elegantno) rešenje, koje smo već videli, je da se šablonska niska smesti unutar funkcije, da se vrednosti koje treba smestiti u šablon predaju kao argument i da na kraju funkcija vraća formiranu nisku (u praksi, ako koristimo mnogo ovakvih funkcija koje sadrže obimne tekstualne obrasce, možemo ih zarad preglednosti smestiti u posebnu .js datoteku).
Korišćenje izraza u šablonskim niskama
Osim identfifikatora promenljivih, u šablonskim niskama možemo korisititi i matematičke izraze, funkcije, elemente nizova i polja objekata:
function sabiranje(a, b) {
return a + b;
}
let x = 9;
let y = 6
let vrednostPI = `${2 + 1}.${sabiranje(9, 5)}${x + y}9265359`;
console.log(vrednostPI);
Jednostavan primer koji prikazuje lepotu programskih jezika.
Šabloni za kreiranje niski u PHP-u (heredoc, nowdoc)
U PHP-u, budući da je u pitanju serverski jezik čija je jedna od osnovnih uloga dinamičko serviranje HTML-a, koncept šablonskih niski koristi se verovatno i više nego u JS-u (doduše, ne pod tim nazivom, već pod drugim nazivima).
U PHP-u, osim korišćenja običnih stringova i operatora konkatenacije, šablone za formiranje stringova moguće je definisati na dva (različita) načina, koji su poznati kao heredoc
i nowdoc
, ali, pre svega, u PHP-u za kreiranje tekstualnih obrazaca koji koriste identifikatore promenljivih sasvim će dobro doći i obične niske (makar kada su u pitanju jednostavniji obrasci koji se zapisuju u jednom redu).
Interpretacija niski uokvirenih navodnicima
U PHP-u se (i inače) podrazumeva da će niske koje su uokvirene navodnicima biti interpretirane, tako što će identifikatori promenljivih biti zamenjeni vrednostima.
Tipičan primer su SQL upiti kakve smo pisali do sada:
<?php
$upit = "SELECT * FROM T1 WHERE email='$ime'";
?>
Prethodno zapisani upit pri pozivu skripte praktično postaje:
SELECT * FROM T1 WHERE email='majaandric@gmail.com'
.... (promenljiva $email zamenjena je svojom vrednošću).
PHP dozvoljava zapis običnih niski u više redova, ali, u tom slučaju, znake navoda je potrebno zapisati preko escape sekvence \""
(u takvim slučajevima koristićemo ipak heredoc
obrasce, kao elegantnije rešenje).
Ispis niski uokvirenih apostrofima
Za razliku od prethodnog zapisa, ako nisku zapišemo unutar apostrofa, vrednosti promenljivih neće biti interpretirane
<?php
echo 'Promenljive se u PHP-u definišu preko znaka "$"';
echo ' (na primer: $a,$b, $upit, $veza).'
?>
Ovo je zgodno kada želimo da prikažemo PHP kod na stranici (kod sa prethodne slike daje sledeći ispis):
Promenljive se u PHP-u definišu preko znaka "$" (na primer: $a,$b, $upit, $veza).
U slučaju niski uokvirenih apostrofima, navodnike ne moramo pisati kao escape sekvence, ali zato apostrofe moramo.
Heredoc
Ako definišemo nisku na sledeći način (dodaćemo i nekoliko promenljivih, da bi kod mogao da proradi, ako ga isprobavate):
<?php
$ime = "Petar";
$prezime = "Marinković";
$email = "peramarinkovic@gmail.com"
$sablon = <<<SABLON
<div class='info'>
<div class='info_red'>
<span>Ime:</span><span>{$ime}</span>
</div>
<div class='info_red'>
<span>Prezime:</span><span>{$prezime}</span>
</div>
<div class='info_red'>
<span>E-mail:</span><span>{$email}</span>
</div>
</div>
SABLON;
echo $sablon;
?>
.... i potom ga pozovemo, dobićemo sledeći ispis:
Ime: Petar
Prezime: Marinković
E-mail: peramarinkovic@gmail.com
Baš kao i u slučaju običnih niski zapisanih između znakova navoda, i ovde će vrednosti promenljivih biti interpretirane, i takođe, kao i u slučaju kada smo koristili JavaScript, pre korišćenja šablona, vrednosti promenljivih koje ćemo koristiti moraju biti definisane unapred.
Da bismo izbegli nedoumice oko toga da li identifikatori koje koristimo u obrascu imaju veze sa promenljivama koje zapravo postoje i imaju vrednost, i ovde ćemo tekstualni obrazac smestiti unutar funkcije (koja se, za razliku od samostalnog heredoc
obrasca, može pozivati bilo gde)
Ovoga puta, funkcija će kao argument primati objekte klase Osoba:
<?php
function formatiranje_podataka_osoba($osoba) {
$sablon = <<<SABLON
<div class='info'>
<div class='info_red'>
<span>Ime:</span><span>${$osoba->ime}</span>
</div>
<div class='info_red'>
<span>Prezime:</span><span>${$osoba->prezime}</span>
</div>
<div class='info_red'>
<span>E-mail:</span><span>${$osoba->email}</span>
</div>
</div>
SABLON;
return $sablon;
}
?>
Kao i do sada, možemo zaključiti da je standardna notacija niski pod navodnicima dovoljna za sitnije zahvate, a da ćemo heredoc format koristiti za veće blokove gde ima puno promenljivih čije vrednosti treba uvrstiti u ispis, pri čemu ćemo koristiti i dodatnu pogodnost što znake navoda možemo pisati neposredno (primetimo da heredoc blok nije uokviren navodnicima ili apostrofima, što, na neki način, sugeriše da navedeni znakovi nemaju poseban značaj u heredoc obrascu).
Ako ne želimo da se vrednosti promenljivih / izraza interpretiraju, već ispišu neposredno (kao u slučaju niksi koje su uokvirene apostrofima) koristićemo takozvani nowdoc format:
Nowdoc
Pri imenovanju nowdoc
obrazaca koristićemo apostrofe ili navodnike (za naziv - u našem slučaju 'SABLON', ali, ne i za tekstualni sadržaj):
<?php
$sablon = <<<'SABLON'
<div class='info'>
<div class='info_red'>
<span>Ime:</span><span>{$ime}</span>
</div>
<div class='info_red'>
<span>Prezime:</span><span>{$prezime}</span>
</div>
<div class='info_red'>
<span>E-mail:</span><span>{$email}</span>
</div>
</div>
SABLON;
echo $sablon;
?>
.... što je poruka PHP interpretatoru da obrazac koi sledi treba tretirati kao običan tekst
Pokretanjem koda sa prethodne slike, dobićemo sledeći ispis:
Ime: {$ime}
Prezime: {$prezime}
E-mail: {$email}
Ovako nešto ćemo koristiti u okolnostima, kada želimo da (doslovno) prikažemo veće blokove teksta koji sadrže PHP kod, ili, onda kada radimo sa niskama u kojima bi inače bilo potrebno uvesti puno escape sekvenci (niske koje sadrže puno znakova kao što su ', ', $ i slično).
Implementacija obrazaca za ispis teksta u Python-u
Najveću pažnju smo posvetili web jezicima, gde se koncept šablonskih niski (reklo bi se) primenjuje češće nego kada su u pitanju desktop aplikacije, ali, nismo zaboravili ni Python i C#.
Koncept šabloniziranog teksta koji koristi vrednosti promenljivih / izraza, u Python-u je (kao i mnogo šta drugo) implementiran na krajnje nenametljiv i jednostavan način, preko takozvanih f-niski:
ime = "Petar"
prezime = "Marinković"
email = "peramarinkovic@gmail.com"
s = f"Ime: {ime}\nPrezime: {prezime}\nE-mail: {email}"
print(s)
Kod iz prethodnog odeljka daje sledeći ispis (primećujemo escape sekvence za prelazak u novi red \n i takođe, sada već dobro poznate vitičaste zagrade koje uokviruju identifikatore promenljivih i izraze):
Ime: Petar
Prezime: Marinković
E-mail: peramarinkovic@gmail.com
Kratko, jednostavno i funkcionalno (uz napomenu da je opcija novijeg datuma i da je dostupna samo u verzijama Pythona 3.x, ali, ne i starijim verzijama).
Implementacija obrazaca za ispis teksta u C#-u
Šablonske niske u C#-u počinju znakom $ i takođe koriste vitičaste zagrade { i }, za definisanje promenljivih / izraza čije vrednosti treba uvrstiti u nisku:
String ime = "Petar";
String prezime = "Marinković";
String email = "peramarinkovic@gmail.com";
String s = $"Ime: {ime}\nPrezime: {prezime}\nE-mail: {email}";
Kao što je bio slučaj i sa prethodnim jezicima, vidimo da je sintaksa jednostavna za pisanje i razumevanje.
Zaključak
Za kraj, imamo želju da vas potaknemo da se malo pozabavite svojevrsnim prepoznavanjem obrazaca u razvoju informacionih tehnologija i razmišljanjem na temu šta je prava svrha računara.
Ako se zapitamo šta je to što pokreće razvoj programa, programskih jezika i pojedinačnih tehnika, rekli bismo da je odgovor na to pitanje: potreba.
Kada postoji realna potreba za nečim, pronađe se i način (naravno, u granicama mogućeg; nećemo tek tako pronaći algoritam za sortiranje nizova čija je složenost O(1), ma koliko da to želimo i da postoji potreba za tim): programski jezici visokog nivo nastali su iz potrebe za jednostavnijim, funckionalnijim i prirodnijim načinom zapisa samih programa, dok su šablonske niske nastale iz potrebe za boljim i prirodnijim načinom zapisa obimnijih kombinovanih niski.
Lepota programiranja je u tome što nam omogućava da ostvarimo velike ideje pod uslovom da "samo" uložimo odgovarajuću (često poveću, ali, tako izgleda mora biti) količinu truda, što je drugačije od većine drugih aktivnosti, gde ostvarivanje velikih ideja često zahteva i velika materijalna ulaganja.
Tema za razmišljanje ....