V tomto textu se zaměříme na pochopení podřetězců v programovacím jazyce Java. Kromě teoretického vysvětlení si ukážeme praktické ukázky kódu, které vám pomohou lépe si danou problematiku vizualizovat. Naučíte se, jak vytvářet podřetězce a jak vyhledávat podřetězce uvnitř existujícího řetězce.
Než se však do toho pustíme, je nutné si ujasnit základní pojmy spojené s podřetězci.
Co jsou to řetězce a podřetězce?
V kontextu Javy je řetězec chápán jako sekvence znaků. Každý řetězec v Javě je reprezentován jako objekt. Řetězce mohou obsahovat písmena, číslice, symboly i mezery. Na druhou stranu, podřetězec je v Javě částí, tedy podmnožinou, existujícího řetězce.
Například „Geek“ je podřetězcem řetězce „etechblog.cz“. Podřetězce nám umožňují získat specifickou část z celého řetězce.
Pokud máte například jméno „Jan Novák“ a potřebujete získat pouze křestní jméno „Jan“, můžete toho snadno dosáhnout pomocí podřetězců. Dalším příkladem může být situace, kdy máte seznam jmen „Jan, Petr, Josef“ a chcete ověřit, zda se v něm nachází jméno „Jan“. I to lze snadno realizovat s použitím podřetězců. Toto jsou pouze ilustrativní příklady. Jakmile pochopíte princip, můžete podřetězce efektivně využívat v mnoha různých operacích.
Nyní, když jsme si ujasnili koncept podřetězců v Javě, se pojďme podívat na to, jak s nimi můžeme pracovat.
#1. Využití metody ‘substring()‘
Metoda ‘substring()‘ nám umožňuje vytvářet podřetězce velmi jednoduše. Tato metoda přijímá jeden nebo dva parametry – buď počáteční index (startIndex), nebo počáteční i koncový index (startIndex a endIndex). Na základě poskytnutých parametrů vrátí požadovaný podřetězec.
V závislosti na počtu zadaných parametrů můžeme tuto metodu použít dvěma způsoby. Pojďme si tyto způsoby podrobněji rozebrat.
substring(int startIndex)
Nejprve se můžeme podívat na metodu ve tvaru ‘substring(startIndex)‘. Tato varianta metody přijímá jako vstup celočíselnou hodnotu, která představuje počáteční pozici podřetězce. Vrací nový řetězec, který začíná na zadaném indexu a pokračuje až do konce původního řetězce.
Podívejme se na následující příklad kódu:
public class Podretezce {
public static void main(String[] args) {
String str = "etechblog.cz";
System.out.println("Původní řetězec: " + str);
System.out.println("Podřetězec: " + str.substring(4));
}
}
VÝSTUP:
Původní řetězec: etechblog.cz
Podřetězec: blog.cz
Z výstupu je zřejmé, že vstupní řetězec byl „etechblog.cz“ a výstupem je podřetězec „blog.cz“. Tento podřetězec začíná na indexu 4 (pátý znak v řetězci) a pokračuje až do konce původního řetězce.
substring(int startIndex, int endIndex)
Další možností použití metody `substring` je zadání dvou celočíselných hodnot, počátečního a koncového indexu. V tomto případě používáme metodu ve tvaru `substring(startIndex, endIndex)`.
Pro lepší pochopení si ukážeme několik příkladů kódu:
public class Podretezce {
public static void main(String[] args) {
String str = "GeekFlareFans";
System.out.println("Původní řetězec: " + str);
System.out.println("Podřetězec: " + str.substring(4, 9));
}
}
VÝSTUP:
Původní řetězec: GeekFlareFans
Podřetězec: Flare
V tomto příkladu, s původním řetězcem „GeekFlareFans“, jsme získali podřetězec „Flare“. Počáteční index byl 4 a koncový index byl 9. Podřetězec tedy začíná na znaku s indexem 4 a končí těsně před znakem s indexem 9. Je důležité si uvědomit, že znak na koncovém indexu není zahrnut v generovaném podřetězci. Podřetězec tedy obsahuje všechny znaky až po koncový index, ale znak na koncovém indexu vylučuje.
#2. Využití metody ‘split()‘
Metoda ‘split()‘ je další metodou třídy String v Javě, která nám pomáhá při vytváření podřetězců. Hodí se zejména v situacích, kdy máme v jednom řetězci uloženo více informací, které jsou odděleny společným oddělovačem.
V syntaxi této metody se setkáme s termínem „regulární výraz“, který může na první pohled působit složitě. Proto si nejprve vysvětlíme, co to regulární výraz je. Regulární výraz (anglicky regular expression, zkráceně regex) je posloupnost znaků, která popisuje určitý vzor v řetězci nebo textu. V kontextu metody `split()` je regulární výraz naším oddělovačem.
Metoda ‘split()‘ může přijímat až dva parametry, a to řetězec reprezentující regulární výraz a celočíselný limit. Regulární výraz je oddělovač. Jakmile je tento oddělovač nalezen, původní řetězec se rozdělí na dvě části – na tu před regulárním výrazem a na tu za ním.
Představme si například, že chceme rozdělit řetězec „abcdef“ pomocí regulárního výrazu „bcd“. Výsledkem by byly dva podřetězce: „a“ a „ef“.
Metoda `split()` vrací pole rozdělených řetězců. Můžeme zadat pouze regulární výraz, nebo regulární výraz spolu s limitem. Pojďme se seznámit s různými způsoby volání této metody.
split(String regex)
První varianta přijímá pouze řetězec reprezentující regulární výraz, ve formátu `split(regex)`. Tato varianta nemá limitní proměnnou, proto vrací všechny oddělené podřetězce v poli.
Pro lepší porozumění se podívejme na následující kód:
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare";
String[] substrings = str.split("%");
System.out.println("Původní řetězec: " + str);
System.out.println("První podřetězec: " + substrings[0]);
System.out.println("Druhý podřetězec: " + substrings[1]);
}
}
VÝSTUP:
Původní řetězec: Geek%Flare
První podřetězec: Geek
Druhý podřetězec: Flare
Jak vidíme z kódu, zadaný řetězec obsahuje oddělovač „%“. Oddělovačem nemusí být pouze jeden znak, může to být libovolný řetězec s libovolným počtem znaků. Metoda `split()` tento regulární výraz ignoruje a vrací všechny řetězce, které byly tímto regulárním výrazem odděleny. Podřetězce jsou uloženy v poli.
V kódu je zadaný řetězec „Geek%Flare“. Získáme tedy pole se dvěma prvky, kterými jsou „Geek“ a „Flare“. Následně k nim přistupujeme pomocí indexů 0 a 1 a vytiskneme je na konzoli.
Je důležité zmínit, že pokud metodě nepředáme žádné parametry, dojde k chybě. Pokud však jako regulární výraz zadáme prázdný řetězec („“), získáme každý jednotlivý znak jako samostatný podřetězec. Pro lepší vizualizaci se podívejme na následující příklad.
import java.util.Arrays;
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare";
String[] substrings = str.split("");
System.out.println(Arrays.toString(substrings));
}
}
VÝSTUP:
[G, e, e, k, %, F, l, a, r, e]
V příkladu je zřejmé, že pokud je parametr regulárního výrazu prázdný řetězec, metoda vrátí všechny znaky jako samostatné podřetězce. To můžeme jasně vidět na výstupu pole z metody `split()`.
split(String regex, int limit)
S druhou variantou této metody získáme větší kontrolu nad výstupem a můžeme jej dále upravit. V této variantě metoda `split()` přijímá dva parametry. Kromě regulárního výrazu zadáváme také limitní parametr ve formátu `split(regex, limit)`.
Parametr ‚limit‘ určuje maximální počet výsledných řetězců, které budou obsaženy ve výstupu. V závislosti na hodnotě limitu mohou nastat tři různé scénáře:
Případ 1: Pokud je limit > 0, výsledné pole bude obsahovat výstup, ale metoda rozdělení se použije maximálně (limit-1) krát. Pole tedy nebude obsahovat více prvků, než je zadaný limit, a veškerý zbývající řetězec, který nebyl rozdělen, bude uložen tak, jak je. Pro lepší pochopení se podívejme na následující příklad.
import java.util.Arrays;
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare%is%the%best";
String[] substrings = str.split("%", 2);
System.out.println(Arrays.toString(substrings));
}
}
VÝSTUP:
[Geek, Flare%is%the%best]
Ve výstupu si můžeme všimnout, že v poli výsledků jsou pouze dva prvky, což odpovídá hodnotě zadané v parametru limit. Také si všimněte, že rozdělení se použije pouze jednou, tedy (limit-1) krát.
Pokud se však regulární výraz vyskytne dvakrát po sobě („%%“), výsledkem budou prázdné podřetězce. Podívejte se na následující kód pro lepší pochopení.
import java.util.Arrays;
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare%is%%the%best%%%";
String[] substrings = str.split("%", 5);
System.out.println(Arrays.toString(substrings));
}
}
VÝSTUP:
[Geek, Flare, is, , the%best%%%]
V podstatě, pokud za „%“ následuje další „%“ nebo konec řetězce, dojde k transformaci na prázdný podřetězec.
Případ 2: Pokud je limit < 0, metoda rozdělení se použije tolikrát, kolikrát je to možné, bez omezení velikosti pole, ale pole bude obsahovat prázdné podřetězce, pokud se regulární výraz vyskytne dvakrát po sobě („%%“).
import java.util.Arrays;
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare%is%%the%best%%%";
String[] substrings = str.split("%", -1);
System.out.println(Arrays.toString(substrings));
}
}
VÝSTUP:
[Geek, Flare, is, , the, best, , , ]
Z výstupu je patrné, že rozdělení je aplikováno tak často, jak je to možné, a prázdné podřetězce jsou také zahrnuty.
Případ 3: Pokud je limit = 0, metoda rozdělení se také použije tolikrát, kolikrát je to možné, ale všechny prázdné podřetězce na konci řetězce budou z pole odstraněny.
import java.util.Arrays;
public class Podretezce {
public static void main(String[] args) {
String str = "Geek%Flare%is%%the%best%%%";
String[] substrings = str.split("%", 0);
System.out.println(Arrays.toString(substrings));
}
}
VÝSTUP:
[Geek, Flare, is, , the, best]
Vidíme, že výstup je podobný případu, kdy limit=-1, ale na konci pole nejsou žádné prázdné podřetězce. Jinými slovy, prázdné podřetězce na konci pole podřetězců jsou ignorovány.
Důležité je také zmínit, že pokud se regulární výraz v řetězci nenachází, metoda vrací jako výsledek původní řetězec.
Zjištění, zda řetězec obsahuje podřetězec
Kromě vytváření podřetězců z existujících řetězců můžeme také ověřit, zda existuje daný podřetězec uvnitř jiného řetězce. To je užitečné v mnoha scénářích. Jak to ale udělat? K tomu nám slouží různé metody. Projdeme si je jednu po druhé.
Použití metody ‘contains()‘
Existence podřetězce v řetězci se dá velmi snadno zjistit pomocí metody `contains()`. Tato metoda třídy String přijímá jako vstup řetězec, který představuje hledaný podřetězec, a vrací booleovskou hodnotu. Tato hodnota indikuje, zda se podřetězec v řetězci nachází, nebo ne. Tuto metodu lze využít v blocích if-else, unárních operátorech a na mnoha dalších místech pro implementaci složitější logiky.
Podívejme se na tuto metodu trochu podrobněji.
public class Podretezce {
public static void main(String[] args) {
String str = "etechblog.cz";
System.out.println("Obsahuje řetězec 'blog'? " + str.contains("blog"));
}
}
VÝSTUP:
Obsahuje řetězec 'blog'? true
Kód ověřuje, zda řetězec „etechblog.cz“ obsahuje slovo „blog“. Po úspěšném nalezení podřetězce metoda vrací booleovskou hodnotu „true“, čímž potvrzuje jeho existenci.
public class Podretezce {
public static void main(String[] args) {
String str = "etechblog.cz";
System.out.println("Obsahuje řetězec 'Flare'? " + str.contains("Flare"));
}
}
VÝSTUP:
Obsahuje řetězec 'Flare'? false
Z tohoto příkladu vyplývá, že pokud podřetězec v řetězci neexistuje, metoda vrátí hodnotu `false`, čímž potvrzuje jeho neexistenci. Tímto způsobem můžeme jednoduše ověřit, zda se v řetězci hledaný podřetězec nachází.
Nalezení pozice podřetězce
#1. Použití metody ‘indexOf()‘
Metodu `indexOf()` můžeme použít k ověření existence podřetězce v řetězci a také k nalezení jeho indexu. Metoda přijímá jako vstup řetězec nebo znak a vrací pozici jeho prvního výskytu. Je však důležité mít na paměti, že je schopna nám poskytnout pouze index prvního výskytu a nemůže potvrdit, zda existují i další výskyty. Dalším důležitým aspektem je fakt, že pokud podřetězec v řetězci neexistuje, metoda vrátí -1.
Pojďme si tuto metodu blíže prozkoumat.
public class Podretezce {
public static void main(String[] args) {
String str = "GeekFlareGeekFlare";
System.out.println("Index podřetězce 'Flare': " + str.indexOf("Flare"));
}
}
VÝSTUP:
Index podřetězce 'Flare': 4
V uvedeném příkladu první výskyt podřetězce „Flare“ začíná na indexu 4 v řetězci „GeekFlareGeekFlare“. Funkce tedy, jak se očekávalo, vrátila index 4.
#2. Použití metody ‘lastIndexOf()‘
Metoda `lastIndexOf()` je velmi podobná metodě `indexOf()`. Obě tyto metody přijímají jako vstup podřetězec a vrací index jeho pozice. Dokonce mají stejnou návratovou hodnotu -1 v případě, že nemohou podřetězec v řetězci najít.
Avšak zatímco `indexOf()` vrací index prvního výskytu podřetězce, `lastIndexOf()` vrací index jeho posledního výskytu.
Podívejme se na příklad v kódu:
public class Podretezce {
public static void main(String[] args) {
String str = "GeekFlareGeekFlare";
System.out.println("Poslední index podřetězce 'Flare': " + str.lastIndexOf("Flare"));
}
}
VÝSTUP:
Poslední index podřetězce 'Flare': 13
Pozorováním výstupu je zřejmé, že metoda `lastIndexOf()` se chová dle očekávání a vrací index posledního výskytu podřetězce „Flare“ v řetězci „GeekFlareGeekFlare“.
Často kladené otázky
Jak mohu použít metodu `split()` k vytvoření neprázdných podřetězců?
Pokud se v původním řetězci objeví více instancí regulárního výrazu za sebou (například „Ahoj%%Hi“, kde regulárním výrazem je „%“), metoda `split()` považuje první výskyt za oddělovač, ale zbytek považuje za prázdné řetězce. Abychom tomu zabránili, můžeme zadat parametr limit jako 0. V tomto případě metoda vrátí pouze neprázdné řetězce.
Vrací `indexOf()` indexy všech výskytů podřetězce?
Ne, `indexOf()` nevrací indexy všech výskytů podřetězce. Metoda `indexOf()` vrací celočíselnou hodnotu reprezentující index prvního výskytu podřetězce. Pokud se však podřetězec v řetězci nenachází, metoda vrátí -1.
Co se stane, pokud jsou zadané indexy v metodě `substring()` mimo rozsah řetězce?
Pokud zadané počáteční a koncové indexy v metodě `substring()` neexistují, kompilátor vyvolá výjimku typu „java.lang.StringIndexOutOfBoundsException“, a program se tedy neprovede.
Závěr
V tomto textu jsme probrali různé metody a koncepty, které jsou klíčové pro práci s podřetězci v Javě. Popsali jsme, jak vytvářet podřetězce a jak ověřovat jejich existenci v řetězcích. Díky těmto informacím byste měli lépe chápat, jak s podřetězci manipulovat. Doporučujeme si projít uvedené příklady a více procvičovat, abyste si důkladně osvojili práci s podřetězci.
Pokud máte zájem o další informace, můžete se podívat na náš seznam otázek z pohovorů v jazyce Java.