Lekce 13 - 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.body.innerHTML += jazyk[0]; // vypíše první znak řetězce document.body.innerHTML += jazyk[4]; // vypíše pátý znak řetězce
Kód výše vypisuje 1. a 5. znak řetězce "JavaScript"
.
Výstup:
V JavaScriptu existuje pro získání znaku na určité pozici
také metoda charAt()
, která funguje úplně stejně a pozici
znaku bere jako parametr. V praxi preferujeme 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.
Znaky na dané pozici jsou v JavaScriptu read-only, nemůžeme je tedy jednoduše změnit. Pro změnu řetězce bychom museli vytvořit nový.
Podřetězce
Nyní si ukážeme, jak pracovat jen s částí řetězce. Těm říkáme podřetězec. Může se jednat např. o slovo, frázi nebo znak.
Metoda substring()
Pomocí substring()
můžeme výříznout část textu od dané
pozice do dané pozice:
let skladatel = "Wolfgang Amadeus Mozart"; document.body.innerHTML += skladatel.substring(9, 16);
Kód výše získá podřetězec od 10. do 16. znaku:
Výstup:
V JS existovala také metoda substr()
, která je
nyní označena jako zastaralá.
Metoda indexOf()
Číselný index pozice nějaké části v textu získáme
pomocí metody indexOf()
. Jako parametr jí předáme hledaný
podřetězec. Metoda vrací index prvního výskytu
podřetězce a pokud jej v řetězci nenajde, vrátí hodnotu
-1
.
Zkusme si vypsat index podřetězců "Script"
, "a"
a "j"
v textu "JavaScript"
:
let jazyk = "JavaScript"; document.body.innerHTML += jazyk.indexOf("Script"); document.body.innerHTML += "<br />"; document.body.innerHTML += jazyk.indexOf("a"); document.body.innerHTML += "<br />"; document.body.innerHTML += jazyk.indexOf("j");
Výstup:
Vidíme, že podřetězec "Script"
byl nalezen na 5. pozici (4.
index). Znak j
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é J
, získali bychom index
0
.
K této metodě existuje analogicky i metoda
lastIndexOf()
, která funguje úplně stejně, ale vrací index
posledního výskytu, tedy hledá od konce řetězce.
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.
Převod znaku na ASCII hodnotu
Zkusme si nyní převést znak "a"
do jeho ASCII hodnoty.
Využijeme k tomu metodu charCodeAt()
, která na libovolném
řetězci vrátí ASCII hodnotu znaku na dané pozici. Jelikož převádíme jen
jeden znak, zadáme pozici 0
:
let znak = "a"; let hodnotaAscii = znak.charCodeAt(0); // Převede znak na jeho ASCII hodnotu document.body.innerHTML += `Znak '${znak}' jsme převedli na ASCII hodnotu ${hodnotaAscii}`;
Výstup:
Převod ASCII hodnoty na znak
Pomocí metody String.fromCharCode()
naopak vytvoříme určitý
znak, když jí v parametru zadáme číselnou ASCII hodnotu tohoto znaku:
let hodnotaAscii = 98; let znak = String.fromCharCode(hodnotaAscii); // Převede ASCII hodnotu na znak document.body.innerHTML += `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"
:
Původní znak | Nový znak (o 1 dále v abecedě) |
---|---|
a | b |
h | i |
o | p |
j | k |
Posun umožníme uživateli vybrat. Pro zájemce zde máme algoritmus podrobněji vysvětlený a to v článku Caesarova šifra. Program si dokonce můžete vyzkoušet v praxi – Online caesarova šifra.
Příprava proměnných
Vraťme se k programování a připravme si kód. Budeme potřebovat proměnné pro:
- text k zašifrování,
- zašifrovanou zprávu
- a pro posun.
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.body.innerHTML += "Původní zpráva: " + puvodniZprava; document.body.innerHTML += "<br />"; let zasifrovanaZprava = ""; let posun = 1;
Příprava cyklu
Dále si připravíme cyklus projíždějící jednotlivé znaky a výpis zašifrované zprávy:
// cyklus projíždějící jednotlivé znaky for (let i = 0; i < puvodniZprava.length; i++) { // ... } // výpis document.body.innerHTML += "Zašifrovaná zpráva: " + zasifrovanaZprava;
Šifrování
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 zas zpět na znak. Tento znak
nakonec připojíme k výsledné zprávě:
// inicializace proměnných let puvodniZprava = "gaiusjuliuscaesar"; document.body.innerHTML += "Původní zpráva: " + puvodniZprava; document.body.innerHTML += "<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.body.innerHTML += "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 259x (3.25 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript