Lekce 12 - Textové řetězce v JavaScriptu podruhé - Práce se znaky
V minulé lekci, Nejčastější chyby JS začátečníků - Umíš pojmenovat proměnné?, jsme si ukázali nejčastější chyby začátečníků v JavaScriptu ohledně pojmenování proměnných.
V dnešním JavaScript tutoriálu se budeme zabývat přístupem k jednotlivým znakům textového řetězce a představíme si další metody pro práci s řetězci.
Textový řetězec
Pokud jste vycítili nějakou podobnost mezi polem a textovým řetězcem,
tak jste vycítili správně. Pro ostatní může být překvapením, že je
datový typ string
v podstatě pole jednotlivých
znaků a můžeme s ním i takto pracovat.
Práce se znaky řetězce
Nejprve si vyzkoušejme, že to všechno funguje. Rozcvičíme se na
jednoduchém vypsání znaku na dané pozici. Jednotlivé znaky v řetězci
můžeme vybrat pomocí indexu. Index se zapisuje do hranatých závorek za
názvem proměnné. Čísluje se od nuly, prvnímu znaku tedy odpovídá index
[0]
:
let jazyk = "JavaScript"; document.write(jazyk[0]); // vypíše první znak řetězce document.write(jazyk[4]); // vypíše pátý znak řetězce
Výstup:
Znaky na dané pozici jsou v JavaScriptu read-only, nemůžeme je tedy jednoduše změnit. Samozřejmě to jde udělat jinak, později si to ukážeme, zatím se budeme věnovat pouze čtení jednotlivých znaků.
Metoda charAt()
Znak na daném indexu můžeme nalézt také pomocí metody
charAt()
. V jejím parametru zadáme index znaku v řetězci (opět
počínaje 0
). Předchozí kód bychom zapsali takto:
let jazyk = "JavaScript"; document.write(jazyk.charAt(0)); document.write(jazyk.charAt(4));
Výstup:
V praxi použijeme spíše první zápis s hranatými
závorkami. Pokud v něm zadáme neplatný index (v našem
případě například číslo 15
), získáme hodnotu
undefined
. Oproti tomu metoda charAt()
v takovém
případě vrátí prázdný řetězec.
Metoda indexOf()
A nyní se podíváme na zjištění pozice daného znaku v
textu. Číselný index této pozice získáme pomocí metody
indexOf()
. Jako parametr jí tedy předáme hledaný znak. Metoda
vrací index prvního výskytu daného znaku a pokud jej v
řetězci nenajde vrátí hodnotu -1
.
Zkusme si vypsat index znaku a
, s
a nějaký znak,
který v textu není, například x
:
let jazyk = "JavaScript"; document.write(jazyk.indexOf("a")); document.write("<br />"); document.write(jazyk.indexOf("s")); document.write("<br />"); document.write(jazyk.indexOf("x"));
Výstup:
Vidíme, že znak s
v textu JavaScript nebyl nalezen. Metoda
indexOf()
totiž rozlišuje mezi velkými a malými písmeny. Pokud
bychom jí v parametru zadali velké S
, získali bychom index
4
.
Metoda lastIndexOf()
Chceme-li zjistit pozici posledního výskytu daného znaku
nebo podřetězce v textu, použijeme metodu lastIndexOf()
:
let jazyk = "JavaScript"; document.write(jazyk.lastIndexOf("a"));
Výstup:
Metoda substring()
Nyní si ještě ukážeme, jak získat vybranou část řetězce, které se říká podřetězec:
let skladatel = "Wolfgang Amadeus Mozart"; document.write(skladatel.substring(9, 16));
Výstup:
V JS existovala také metoda substr()
, která je
nyní označena jako zastaralá.
ASCII hodnota
Možná jste již někdy slyšeli o ASCII tabulce. Zejména v éře
operačního systému MS-DOS prakticky nebyla jiná možnost, jak zaznamenávat
text. Jednotlivé znaky byly uloženy jako čísla typu byte
, tedy
s rozsahem hodnot od 0
do 255
. V systému byla
uložena tzv. ASCII tabulka, která měla také 256 znaků a každému ASCII
kódu (číselnému kódu) přiřazovala jeden znak.
Asi je vám jasné, proč tento způsob nepřetrval dodnes. Do tabulky se
jednoduše nevešly všechny znaky všech národních abeced, nyní se
používá Unicode (UTF-8) kódování, kde jsou znaky reprezentovány trochu
jiným způsobem. Nicméně máme stále možnost pracovat s ASCII hodnotami
jednotlivých znaků. Hlavní výhoda je v tom, že znaky jsou uloženy v
tabulce za sebou, podle abecedy. Např. na pozici 97
nalezneme znak
a
, na pozici 98
znak b
a podobně.
Podobně je to s čísly, diakritické znaky tam budou bohužel jen nějak
rozházeny.
Zkusme si nyní převést znak do jeho ASCII hodnoty. Využijeme k tomu
metodu charCodeAt()
a jako parametr jí zadáme index
0
:
let znak = "a"; let hodnotaAscii = znak.charCodeAt(0); // Převede znak na jeho ASCII hodnotu document.write(`Znak '${znak}' jsme převedli na ASCII hodnotu ${hodnotaAscii}`);
Výstup:
Pomocí metody String.fromCharCode()
naopak vytvoříme určitý
znak, když jí v parametru zadáme číselnou ASCII hodnotu:
let hodnotaAscii = 98; let znak = String.fromCharCode(hodnotaAscii); // Převede ASCII hodnotu na znak document.write(`ASCII hodnotu ${hodnotaAscii} jsme převedli na znak '${znak}'`);
Výstup:
Caesarova šifra
Nakonec si vytvoříme jednoduchý program pro šifrování textu. Pokud jste
někdy slyšeli o Caesarově šifře, bude to přesně to, co si zde
naprogramujeme. Šifrování textu spočívá v posouvání znaku v abecedě o
určitý, pevně stanovený, počet znaků. Například slovo ahoj
se s posunem textu o 1
přeloží jako "bipk"
. Posun
umožníme uživateli vybrat. Algoritmus zde máme samozřejmě opět
vysvětlený a to v článku Caesarova
šifra. Program si dokonce můžete vyzkoušet v praxi - Online caesarova
šifra.
Vraťme se k programování a připravme si kód. Budeme potřebovat proměnné pro:
- původní text,
- zašifrovanou zprávu
- a pro posun.
Dále si připravíme cyklus projíždějící jednotlivé znaky a výpis zašifrované zprávy. Zprávu si necháme zapsanou napevno v kódu, abychom ji nemuseli při každém spuštění programu psát. Šifra nepočítá s diakritikou, mezerami a interpunkčními znaménky:
// inicializace proměnných let puvodniZprava = "gaiusjuliuscaesar"; document.write("Původní zpráva: " + puvodniZprava); document.write("<br />"); let zasifrovanaZprava = ""; let posun = 1; // cyklus projíždějící jednotlivé znaky for (let i = 0; i < puvodniZprava.length; i++) { // ... } // výpis document.write("Zašifrovaná zpráva: " + zasifrovanaZprava);
Nyní se přesuneme dovnitř cyklu, v něm postupně získáme ASCII hodnotu
(neboli ordinální hodnotu) jednotlivých znaků, tuto hodnotu pokaždé
zvýšíme o posun
a převedeme na znak. Tento znak nakonec
připojíme k výsledné zprávě:
// inicializace proměnných let puvodniZprava = "gaiusjuliuscaesar"; document.write("Původní zpráva: " + puvodniZprava); document.write("<br />"); let zasifrovanaZprava = ""; let posun = 1; // cyklus projíždějící jednotlivé znaky for (let i = 0; i < puvodniZprava.length; i++) { let ascii = puvodniZprava.charCodeAt(i); ascii += posun; let znak = String.fromCharCode(ascii); zasifrovanaZprava += znak; } // výpis document.write("Zašifrovaná zpráva: " + zasifrovanaZprava);
Výstup programu:
Program si vyzkoušíme. Výsledek vypadá docela dobře. Zkusme si však
zadat vyšší posun nebo napsat slovo zebra
. Vidíme, že znaky
mohou po z
přetéct do ASCII hodnot dalších znaků, v textu tedy
již nemáme jen písmena, ale další ošklivé znaky.
Doplnění kontroly přetečení
Problém vyřešíme tím, že uzavřeme znaky do kruhu tak, aby posun
plynule po znaku z
přešel opět ke znaku a
a
podobně. Postačí nám k tomu jednoduchá podmínka, která od nové ASCII
hodnoty odečte celou abecedu tak, abychom začínali opět na a
.
Upravený cyklus bude vypadat takto:
for (let i = 0; i < puvodniZprava.length; i++) { let ascii = puvodniZprava.charCodeAt(i); ascii += posun; // Kontrola přetečení if (ascii > "z".charCodeAt(0)) { ascii -= 26; } let znak = String.fromCharCode(ascii); zasifrovanaZprava += znak; }
Pokud hodnota proměnné ascii
přesáhne ASCII hodnotu
z
, snížíme ji o 26
znaků (tolik znaků má
anglická abeceda). Operátor -=
vykoná to samé, jako bychom
napsali ascii = ascii - 26
. Je to jednoduché a náš program je
nyní funkční.
Jako původní zprávu nastavíme text zebra
a v prohlížeči
pak program znovu spustíme:
Všimněme si, že nikde nepoužíváme přímé kódy znaků, v podmínce je
ascii > "z".charCodeAt(0)
, i když bychom tam mohli napsat
rovnou 122
. Je to z důvodu, aby byl náš program plně odstíněn
od explicitních ASCII hodnot a bylo lépe viditelné, jak funguje. Cvičně si
zkuste udělat dešifrování
V příští lekci, Textové řetězce v JavaScriptu do třetice - Split a join, si ukážeme, že string
umí přeci
jen ještě něco navíc. Prozradím, že budeme dekódovat Morseovu
abecedu.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 122x (2.94 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript