287 lines
17 KiB
Markdown
287 lines
17 KiB
Markdown
# Řetězce a práce s nimi
|
||
|
||
- Třída ```String```
|
||
- Jedna z nejpoužívanějších tříd z Java Core API
|
||
- Řetězcové konstanty (literály – texty uzavřené do uvozovek, např. "Ahoj") používáme od začátku předmětu KIV/PPA1
|
||
|
||
### Specifické vlastnosti třídy String
|
||
|
||
- ```String``` je třída, jednotlivé řetězce (tj. texty) jsou její instance uložené na haldě (na heapu)
|
||
- Z praktických důvodů má však některé vlastnosti, které u jiných tříd nejsou
|
||
|
||
#### Vytvoření řetězce bez operátoru new
|
||
|
||
- Jak bylo vidět ve všech příkladech, které dosud vypisovaly text, instance třídy ```String``` může vzniknout i bez operátoru ```new```
|
||
- Vznikne zápisem literálu (nepojmenované konstanty)
|
||
- Např. ```String pozdrav = "Ahoj!";```
|
||
- Např. ```System.out.println("Nazdar!");```
|
||
- Tento postup jsme používali dosud (aniž jsme věděli o tom, že vznikají instance třídy ```String```)
|
||
- Tento postup se používá běžně
|
||
- Je možné i přímo vytvořit novou instanci třídy String operátorem ```new```
|
||
- Třída ```String``` obsahuje několik konstruktorů umožňující vytvořit řetězec z pole znaků, pole bytů, atd.
|
||
- Je možné i vytvořit nový řetězec z jiného řetězce
|
||
- Např. ```String pozdrav = new String("Ahoj!");```
|
||
- Tento zápis NEPOUŽÍVAT
|
||
- Protože samotný zápis literálu "```Ahoj```" způsobí vytvoření nové instance třídy ```String```, volání new ```String()``` zbytečně vytvoří další instanci
|
||
|
||
#### Konstantnost řetězce
|
||
|
||
- Řetězce v Javě (tj. instance třídy ```String```) jsou konstantní, neměnné (immutable)
|
||
- Nelze do nich přidávat text, mazat, nebo měnit jednotlivé znaky
|
||
- Veškeré metody zdánlivě upravující řetězec ve skutečnosti vytvoří novou instanci třídy ```String``` a text v původní instanci zůstane nedotčen
|
||
- Existují třídy pro práci s měnitelným řetězcem
|
||
- Třída StringBuilder
|
||
- Třída StringBuffer
|
||
- Přesto si ve většině případů vystačíme s třídou ```String```
|
||
- To, že při změně obsahu řetězce dojde k vytvoření nové instance a původní zůstane nezměněná, nám nevadí (v podstatě si toho nevšimneme)
|
||
|
||
#### Spojení řetězců pomocí operátoru „+“ (zřetězení)
|
||
|
||
- Od začátku jsme běžně používali
|
||
- Především v metodě ```System.out.println()```
|
||
- Operátor „+“ spojí dva řetězce (operandy) a vytvoří novou instanci obsahující texty obou řetězců (operandů)
|
||
- Operátor „+“ také umožňuje připojit k řetězci libovolný datový typ
|
||
- Hodnota daného typu se převede na řetězec
|
||
- Alespoň jeden operand musí být řetězec, pokud ne, má operátor „+“ význam sčítání
|
||
- Pro přehlednost je lepší začínat řetězcem, pokud nechceme začínat uvozujícím textem, lze použít prázdný řetězec
|
||
- Časté je použití přímo v metodě ```System.out.println()```
|
||
|
||
### Práce s řetězci
|
||
|
||
- Metody pro práci s řetězci jsou převážně **metody instance třídy String**
|
||
- Proto se volají nad referenční proměnnou ukazující na instanci řetězce
|
||
- ```referenčníProměnná.názevMetody(parametry);```
|
||
- Např. ```pozdrav.charAt(0);```
|
||
- Stejné jako u jiných objektů
|
||
- Protože instance řetězce vznikne pouhým zapsáním literálu, lze nad ním rovnou volat metody bez nutnosti použití referenční proměnné
|
||
- Např. ```"Ahoj".charAt(0); //Funkcni ale nepouzivat```
|
||
- NEPOUŽÍVAT!
|
||
|
||
#### Práce s jednotlivými znaky a délka řetězce
|
||
|
||
- Řetězec si lze představit jako speciální konstantní pole znaků
|
||
- Ale jedná se o instanci třídy, nelze s ní pracovat jako s polem – tj. přistupovat k jednotlivým znakům pomocí hranatých závorek „[“ a „]“
|
||
- Pole znaků (tj. ```char[]```) je uvnitř řetězce skutečně obsaženo
|
||
- Pro následující příklady předpokládejte deklaraci
|
||
- ```String pozdrav = "Nazdar";```
|
||
- Délka řetězce
|
||
- Metoda ```length()```
|
||
- POZOR! – Je to metoda, nikoliv proměnná, jako u polí (tj. musí se uvést závorky)
|
||
- Vrací počet znaků řetězce (včetně bílých znaků)
|
||
- ```int delka = pozdrav.length(); //delka bude 6```
|
||
- Znak na zadané pozici
|
||
- Metoda ```charAt(indexZnaku)```
|
||
- Znaky mají index podobně jako prvky pole číslované od 0 do délka řetězce - 1
|
||
- ```char znak = pozdrav.charAt(0); //znak bude 'N'```
|
||
- Index prvního výskytu znaku/podřetězce
|
||
- Metoda ```indexOf(znak/podřetězec)```
|
||
- Vrátí index prvního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen
|
||
- ```int index1 = pozdrav.indexOf('a'); //index1 bude 1```
|
||
- ```int index2 = pozdrav.indexOf("zd"); //index2 bude 2```
|
||
- ```int index3 = pozdrav.indexOf("j"); //index3 bude -1```
|
||
- Index posledního výskytu znaku/podřetězce
|
||
- Metoda ```lastIndexOf```(```znak/podřetězec```)
|
||
- Vrátí index posledního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen
|
||
- ``int li1 = pozdrav.lastIndexOf('a'); //li1 bude 4``
|
||
- ```int li2 = pozdrav.lastIndexOf("Na "); //li2 bude 0 ```
|
||
- Náhrada všech výskytů znaku v řetězci
|
||
- Metoda ```replace(puvodníZnak, novýZnak)```
|
||
- ```String s2 = pozdrav.replace('a', 'e'); //"Nezder"```
|
||
|
||
#### Porovnání řetězců
|
||
|
||
- Řetězce jsou instance třídy ```String```
|
||
- Porovnání pomocí operátoru „```==```“, pouze zjistí, zda se jedná o stejné instance **nepoužívat**
|
||
- **Porovnání podle obsahů** (důsledně včetně velikosti písmen) – **shodné/rozdílné**
|
||
- Metoda ```equals```(```jinýŘetězec```)
|
||
- Výsledek ```true``` (řetězce jsou shodné) nebo ```false``` (řetězce jsou rozdílné)
|
||
- Porovnání podle obsahů **bez ohledu na velikost písmen** – **shodné/rozdílné**
|
||
- Metoda ```equalsIgnoreCase```(```jinýŘetězec```)
|
||
- Výsledek ```true``` (řetězce jsou shodné bez ohledu na velikost písmen) nebo ```false``` (řetězce jsou rozdílné bez ohledu na velikost písmen)
|
||
- Porovnání podle obsahů (**důsledně včetně velikosti písmen**) – **větší/menší/stejný**
|
||
- Metoda ```compareTo```(```jinýŘetězec```)
|
||
- Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je dále od začátku abecedy)
|
||
- Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je blíže konci abecedy)
|
||
- POZOR! – Návratové hodnoty metod ```compareTo…()```
|
||
- Vrácené záporné a kladné číslo (když řetězce nejsou shodné) nemusí být (a není) jen -1 nebo 1
|
||
- Návratovou hodnotu metody je třeba porovnávat pomocí operátorů „>“ a „<“, nikoliv porovnáním operátorem „==“ s -1 či 1
|
||
- **Test začátku a konce řetězce**
|
||
- Výsledek ```true```, pokud řetězec začíná/končí zadaným podřetězcem, jinak vrací ```false```
|
||
- Metoda ```startsWith(prefix)```
|
||
- Metoda ```endsWith(postFix)```
|
||
- Metoda ```startsWithIgnoreCase(prefix)```
|
||
- Metoda ```endsWithIgnoreCase(postFix)```
|
||
|
||
#### Získání podřetězce z řetězce
|
||
|
||
- Stále předpokládáme deklaraci ```String pozdrav = "Nazdar";```
|
||
- Získání podřetězce od zadaného indexu (**včetně**) do konce
|
||
- Metoda ```substring(indexOd)```
|
||
- ```String p1 = pozdrav.substring(2); //p1 bude "zdar"```
|
||
- Získání podřetězce od zadaného indexu (**včetně**) do zadaného indexu (**vyjma**)
|
||
- Metoda ```substring(indexOd, indexDo)```
|
||
- ```String p2 = pozdrav.substring(0, 2); //p2 bude "Na"```
|
||
- Odstranění bílých znaků ze začátku a konce řetězce
|
||
- Metoda ```trim()```
|
||
- Uvažujme deklaraci ```String bz = "\r\n \tahoj \t\n\r";```
|
||
- ```String oriznuty = bz.trim(); //oriznuty bude "ahoj"```
|
||
|
||
### Konverze řetězce na jiné datové typy a obráceně
|
||
|
||
- Relativně časté operace
|
||
- **Převod řetězce na číselný datový typ**
|
||
- Typicky při vstupu (když nepoužíváme Scanner, nebo je vstup komplikovanější, nebo v GUI)
|
||
- Číselný datový typ je potřeba, abychom mohli provádět aritmetické operace
|
||
- ```Např. "1" + "2" je řetězec "12", ale 1 + 2 je 3```
|
||
- **Převod čísla na řetězec**
|
||
- Implicitně se provádí při každém výstupu
|
||
- Explicitně, když chceme využít operace nad řetězci např. pro čísla (např. zjištění počtu znaků (tj. číslic), zřetězení s řetězcem)
|
||
- **Převod instance (objektu) na řetězec**
|
||
- Pokud chceme instanci vypsat
|
||
|
||
#### Konverze řetězce na jiné datové typy
|
||
|
||
- Pro základní datové typy se používá metoda ```Typ.parseTyp(řetězec)``` z příslušné obalovací třídy základního datového typu
|
||
- Jedná se o metody třídy, volá se s názvem třídy, není potřeba vytvářet instanci
|
||
- Např. ```int i = Integer.parseInt("42");```
|
||
- Např. ```long l = Long.parseLong("2444111333");```
|
||
- Např. ```double d = Double.parseDouble("5.972E24");```
|
||
- Např. ```boolean b = Boolean.parseBoolean("false");```
|
||
- Pro objekty
|
||
- Není žádný standardní a obecný postup pro převod řetězce na instanci jiné třídy
|
||
|
||
#### Konverze jiných datových typů na řetězec
|
||
|
||
- Běžně se využívá schopnost operátoru zřetězení „+“ převádět jiné datové typy (základní datové typy a instance tříd) na řetězec
|
||
- Pro základní datové typy funguje přímočaře
|
||
- Pro objekty také – objekt se převede na řetězec implicitním voláním metody ```toString()```
|
||
- Pokud je metoda ```toString()``` překryta, funguje dobře
|
||
- Pro pole je potřeba použít metodu třídy ```Arrays.toString(pole)```
|
||
- Pokud se použije pouze operátor „+“, použije se implicitní textová reprezentace pole (např. ```[I@15db9742```)
|
||
- Pro základní datové typy existuje další možnost – metoda ```Typ.toString (hodnota)``` z příslušné obalovací třídy základního datového typu
|
||
- Např. ```String s = Integer.toString(42); //s bude "42"```
|
||
- Pro základní datové typy a pro instance tříd existuje další možnost – metoda třídy ```valueOf(hodnota)``` třídy ```String```
|
||
- Metoda je překrytá pro všechny základní datové typy a objekty
|
||
- Např. ```String s = String.valueOf(42) //s bude "42"```
|
||
|
||
### Rozdělení řetězce na podřetězce
|
||
|
||
- Často je potřeba **rozdělit řetězec na několik podřetězců** podle oddělovače (mezer, bílých znaků, čárek, teček, pomlček či jiné interpunkce či jiného znaku)
|
||
- Metoda instance ```split(regulárníVýraz)``` ve třídě ```String```
|
||
- Metoda má jako parametr regulární výraz
|
||
- Regulární výraz
|
||
- Řetězec popisující celou množinu řetězců => mnohé znaky tak mají speciální význam
|
||
- Parametrem tedy není jen znak, podle kterého se má řetězec rozdělit
|
||
- Některé znaky (např. mezera) nemají speciální význam a lze je tak použít bez problémů (tj. ```split(" ")```)
|
||
- Některé znaky mají speciální význam a je třeba použít tzv. „escape“ sekvenci
|
||
- Zpětné lomítko „\“ před znak, který chceme použít => zruší se tím speciální význam znaku
|
||
- Protože však zpětné lomítko má speciální význam i v řetězcových a znakových literálech (umožňuje napsat speciální znaky, např. konec řádky „\n“), je třeba napsat zpětná lomítka
|
||
- Metoda vrací pole řetězců, délka pole záleží na počtu podřetězců dvě „\\“
|
||
|
||
### Proměnný řetězec
|
||
|
||
- V některých případech (ač jich není mnoho) opravdu potřebujeme, aby se při každé změně textu řetězce nevytvářela nová instance => je potřeba měnitelný (mutable) řetězec
|
||
- Pokud provádíme v řetězci mnoho změn a použili bychom třídu ```String```, **vytvářelo by se mnoho instancí** – pro každou změnu se vytvoří nová, což zbytečně zabírá paměť a zpomaluje program (vytvoření instance nějakou dobu trvá)
|
||
- Pokud by šel **řetězec měnit**, vystačíme si s jednou instancí
|
||
|
||
#### Třída StringBuilder
|
||
|
||
- **Proměnný/měnitelný řetězec** (sekvence znaků)
|
||
- Vytvoření instance třídy ```StringBuilder```
|
||
- Lze zadat řetězec, nebo kapacitu
|
||
- Kapacita se udává kvůli efektivitě – pokud je dostatečná, nemusí se během práce s řetězcem (při jeho prodloužení) kapacita navyšovat
|
||
- Je však možné do instance třídy ```StringBuilder``` vložit/přidat řetězec nebo jiný datový typ (viz níže) a překročit aktuální kapacitu kapacita se automaticky navýší
|
||
- Např. ```StringBuilder sb1 = new StringBuilder("Ahoj");```
|
||
- Např. ```StringBuilder sb2 = new StringBuilder(100);```
|
||
- Práce se znaky
|
||
- Zjištění konkrétního znaku
|
||
- Metoda ```charAt(index)```
|
||
- Vrátí znak na zadaném indexu
|
||
- Např. ```int i = sb1.charAt(3); //'o'```
|
||
- Nastavení konkrétného znaku
|
||
- Metoda ```setCharAt(index, znak)```
|
||
- Nastaví znak na zadaném indexu na zadaný znak
|
||
- Např. ```sb1.setCharAt(0, 'E'); //"Ehoj"```
|
||
- Délka řetězce
|
||
- Zjištění délky uloženého řetězce
|
||
- Metoda ```getLength()```
|
||
- Vrátí délku řetězce
|
||
- Např. ```int d1 = sb1.getLength(); //4```
|
||
- Např. ```int d2 = sb2.getLength(); //0```
|
||
- Nastavení délky řetězce
|
||
- Metoda ```setLength(délka)```
|
||
- Nastaví délku řetězce
|
||
- Pokud se řetězec prodlužuje, přidané znaky budou mít hodnotu 0
|
||
- Pokud se řetězec zkracuje, znaky nad zadanou délku se oříznou
|
||
- Např. ```sb2.setLength(10); //10 znaků hodnoty 0```
|
||
- Např. ```sb2.setLength(0); //Prazdny retezec```
|
||
- Převrácení řetězce
|
||
- Metoda ```reverse()```
|
||
- Převrátí pořadí znaků
|
||
- Např. ```sb1.reverse(); //"johE"```
|
||
- Přidání/vložení libovolného datového typu
|
||
- Přidání libovolného datového typu
|
||
- Metoda ```append(hodnota)```
|
||
- Metoda překryta pro všechny základní datové typy, ```Object```, ```String``` a ```StringBuilder```
|
||
- Např. ```sb2.append(true); //"true"```
|
||
- Např. ```sb1.append(sb2); //"johEtrue"```
|
||
- Vložení libovolného datového typu
|
||
- Metoda ```insert(index, hodnota)```
|
||
- Metoda překryta pro všechny základní datové typy, ```Object``` a ```String```
|
||
- Znaky na pozici ```index``` a dále se odsunou o počet vložených znaků
|
||
- Např. ```sb1.insert(3, 42); //"joh42Etrue"```
|
||
- Smazání podřetězce či znaku
|
||
- Smazání podřetězce
|
||
- Metoda ```delete(začátek, konec);```
|
||
- Smaže podřetězec začínající na pozici začátek a končící před pozicí ```konec```
|
||
- Např. ```sb1.delete(2, 5); //"joEtrue"```
|
||
- Smazání znaku
|
||
- Metoda ```deleteCharAt(index)```
|
||
- Smaže znak na zadaném indexu
|
||
- Např. ```sb1.deleteCharAt(2); //"jotrue"```
|
||
|
||
#### Třída StringBuffer
|
||
|
||
- Proměnný/měnitelný řetězec (sekvence znaků), která má téměř stejné metody a téměř stejné použití jako třída ```StringBuilder```
|
||
- Starší a pomalejší
|
||
- Vhodný, pokud má s proměnným řetězcem pracovat více vláken (viz předmět KIV/PGS)
|
||
|
||
### Třída Character
|
||
|
||
- Obalovací třída pro základní datový typ ```char```
|
||
- Obsahuje mnoho konstant důležitých pro práci s různými speciálními znaky (např. z jiných abeced než latinky)
|
||
- Obsahuje mj. metody pro určení typu znaku
|
||
|
||
#### Určení typu znaku
|
||
|
||
- Metody pro určení typu znaku třídy ```Character```
|
||
- Jedná se o metody třídy, volají se nad názvem třídy, vrací ```true```, pokud znak je daného typu (podle názvu metody), jinak vrací ```false```
|
||
- Metody pracují správně i pro speciální znaky (které např. nejsou z latinky)
|
||
- Metoda ```isDigit(znak)```
|
||
- Zjistí, jestli je zadaný znak číslice
|
||
- Např. ```Character.isDigit('3'); //true```
|
||
- Např. ```Characet.isDigit('A'); //false```
|
||
- Metoda ```isLetter(znak)```
|
||
- Zjistí, jestli je zadaný znak písmeno
|
||
- Např. ```Character.isLetter('3'); //false```
|
||
- Např. ```Character.isLetter('A'); //true```
|
||
- Metoda ```isLetterOrDigit(znak)```
|
||
- Zjistí, jestli je zadaný znak písmeno nebo číslice
|
||
- Např. ```Character.isLetterOrDigit('3'); //true```
|
||
- Např. ```Character.isLetterOrDigit('A'); //true```
|
||
- Metoda ```isWhitespace(znak)```
|
||
- Zjistí, jestli je zadaný znak bílý znak
|
||
- POZOR! – druhé „```s```“ v názvu metody je také malé
|
||
- Např. ```Character.isWhitespace(' '); //true```
|
||
- Např. ```Character.isWhitespace('\n'); //true```
|
||
- Metoda ```isLowerCase(znak)```
|
||
- Zjistí, jestli je zadaný znak malé písmeno
|
||
- Např. ```Character.isLowerCase('a'); //true```
|
||
- Např. ```Character.isLowerCase('A'); //false```
|
||
- Např. ```Character.isLowerCase('3'); //false```
|
||
- Metoda ```isUpperCase(znak)```
|
||
- Zjistí, jestli je zadaný znak velké písmeno
|
||
- Např. ```Character.isUpperCase('a'); //false```
|
||
- Např. ```Character.isUpperCase('A'); //true```
|
||
- Např. ```Character.isUpperCase('3'); //false```
|
||
|