IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

9. diel - Textové reťazce v Swift do tretice - Split a joined

V predchádzajúcom cvičení, Riešené úlohy k 8. lekcii Swift, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V kurze sme si v minulej lekcii, Riešené úlohy k 8. lekcii Swift , ukázali, že String je vlastne pole znakov. Dnes si vysvetlíme ďalšie metódy na reťazci, ktoré som vám zámerne zatajil, pretože sme nevedeli, že String je vlastne pole :)

Na reťazci môžeme používať mnoho metód alebo vlastností, ktoré poznáme z poľa. Sú to napr: first, last, index() a ďalšie.

Keď si vytvoríme ľubovoľnú premennú a napíšeme za ňu bodku, Xcode nám zobrazí ponuku všetkých metód a vlastností (a tiež premenných, ale k tomu sa dostaneme až pri objektoch), ktoré na ňu môžeme volať. Skúsme si to:

Pomoc metód na reťazci v Xcode - Základné konštrukcie jazyka Swift

Tú istú ponuku možno vyvolať aj stlačením Ctrl + Medzerník v prípade, že textový kurzor umiestnime na bodku. Samozrejme to platí pre všetky premenné aj triedy a budeme toho využívať čoraz častejšie. Metódy sú radené abecedne a môžeme nimi listovať pomocou kurzorových šípok. Xcode nám zobrazuje opis metód (čo robia) a aké vyžadujú parametre.

Povedzme si o nasledujúcich metódach a ukážme si ich na jednoduchých príkladoch:

Ďalšie metódy na reťazci

insert()

Vloží podreťazec do reťazca na určitú pozíciu. Parametre sú pozície v reťazci a podreťazec.

var text = "Ja by som všetky tie internety zakázala."
text.insert(contentsOf: "nie", at: text.index(text.startIndex, offsetBy: 29))
print(text)

výstup:

Ja by som všetky tie internety nezakázala.

remove() a removeSubrange()

Metóda remove() je jednoduchšie, ale vie odstrániť iba jeden znak na nami zadanom indexe. Index opäť musí byť zadaný ako dátový typ String.Index, ktorý sme už stretli. removeSubrange() odstráni ľubovoľný podreťazec nášho reťazca, ale opäť ho musíme zadať pomocou String.Index a aby toho nebolo málo, tak ešte cez dátový typ Range.

Range je prakticky interval "od-do" a zapisuje sa pomocou trojice bodiek. Už sme sa s ním stretli u cyklov :-) for i in 1...5, pamätáte? Podobne v ňom možno vytvoriť Range z String.Index. Nižšie si ukážeme niekoľko príkladov.

var text = "Kto sa smeje naposledy, ten je admin."
text.remove(at: text.startIndex)
print(text)

výstup:

do sa smeje naposledy, ten je admin.

A príklad na removeSubrange():

var text = "Kto sa smeje naposledy, ten je admin."
text.removeSubrange(text.index(text.startIndex, offsetBy: 3)..<text.endIndex)
print(text)

výstup:

Kto

Všimnite si, že v Range musíme použiť operátor < (menší ako), pretože inak by sme sa cez endIndex dostali o jednu pozíciu mimo String a program by spadol.

Substring

Substring slúži k získaniu časti reťazca zo String. Skoršie verzie Swiftu ponúkali rovnomennú metódu. Tá je ale zastaraná a novo k získaniu substring slúži hranaté zátvorky. Tomuto sa hovorí "slicing", skrátka také krájanie reťazcov. Opäť si ukážeme niekoľko príkladov a potom ich vysvetlíme.

let text = "Kto sa smeje naposledy, ten je admin."
let endIndex = text.index(of: ",")!
let substring = String(text[...endIndex])
print(substring)

výstup:

Kto sa smeje naposledy,

Skúsme si ďalší príklad:

let text = "Kto sa smeje naposledy, ten je admin."
let startIndex = text.index(of: ",")!
let substring = String(text[startIndex...])
print(substring)

výstup:

, ten je admin.

A posledná:

let text = "Kto sa smeje naposledy, ten je admin."
let startIndex = text.index(text.startIndex, offsetBy: 3)
let endIndex = text.index(startIndex, offsetBy: 9)
let substring = String(text[startIndex...endIndex])
print(substring)

výstup:

sa smeje

Ako sami určite vidíte, opäť musíme pracovať s typmi String.Index, takže celý kód zaberá viac riadkov. Tiež sme využili Range obmedzené iba z jednej strany. Takto môžete vziať celý substring od určitého indexu či po určitý index. V poslednom príklade sme využili štandardnú Range obmedzené z oboch strán a tiež sme endIndex získali za pomoci toho štartového.

Všetky tieto slicing operácie nevracia priamo String, ale typ Substring, ktorý je najlepší hneď previesť späť na String. Odporúča to priamo Apple v dokumentácii a jedným z dôvodov je, že Substring si v pamäti drží pôvodnej String, hoci my s ním neplánujeme pracovať.

compare()

Metóda umožňuje porovnať dva reťazce podľa abecedy. Výsledok porovnania získame skrze vlastnosť rawValue. Vracia -1 ak je reťazec pred reťazcom prenášaným parametra, 0 ak sú rovnaké a 1 ak je za ním:

print("akát".compare("blýskavice").rawValue)

výstup:

-1

Poďme sa teraz pozrieť na 2 ďalšie metódy na String, ktoré sú naozaj veľmi užitočné.

split() a joined()

Z predchádzajúcej lekcie vieme, že parsování reťazca znak po znaku môže byť niekedy celkom zložité a to sme robili pomerne jednoduchý príklad. S reťazci sa samozrejme budeme stretávať stále, a to ako na vstupe od užívateľa (napr. Z konzoly alebo z polí v "okenných aplikáciách), tak v súboroch TXT a XML. Veľmi často máme zadaný jeden dlhší String (riadok súboru alebo riadok konzoly) , v ktorom je viac hodnôt, oddelených tzv. separátory, napr. čiarkou. v tomto prípade hovoríme o formáte "CSV" (Comma-Separated Values, teda hodnoty oddelené čiarkou). aby sme si boli istí, že vieme, o čom hovoríme, ukážme si nejaké ukážkové reťazca:

Jan,Novák,Dlhá 10,Praha 3,130 00
.. ... .-.. .- -. -.. ... --- ..-. -
(1,2,3;4,5,6;7,8,9)
  • Prvý reťazec je očividne nejaký užívateľ, takto by sme mohli napr. Realizovať uloženie užívateľov do CSV súboru, každý na jeden riadok.
  • Druhý reťazec sú znaky Morseovej abecedy, separátor (oddeľovač) je tu medzera.
  • Tretí reťazec je matica o 3 stĺpcoch a 3 riadkoch. Oddeľovač stĺpcov je čiarka, riadkov bodkočiarka.

Na String môžeme volať metódu split(), ktorá berie ako parameter separátor (typu Character). Následne pôvodnej reťazec rozdelí podľa separátora na pole podreťazcov, ktoré vráti. To nám veľmi uľahčí prácu pri rozdeľovaní hodnôt v reťazci.

Metóda joined() nám naopak umožňuje pole podreťazcov spojiť oddeľovačom do jediného reťazca, parameter je oddeľovač. Výstupom metódy je výsledný reťazec. Metódu môžeme zavolať bez parametra a tým dôjde k spojeniu reťazcov bez oddeľovača.

Keďže nevieme tvoriť objekty (používateľa) a ani pracovať s viacrozmernými poliami (matice), skúsime si naprogramovať dekodér správ z Morseovej abecedy.

Dekodér Morseovej abecedy

Poďme si opäť pripraviť štruktúru programu. Budeme potrebovať 2 reťazca so správou, jeden so správou v Morseovej abecede, druhý zatiaľ prázdny, do ktorého budeme ukladať výsledok nášho snaženia. Ďalej budeme ako v prípade samohlások potrebovať nejaký vzor písmen. K písmenám samozrejme vzor ich znaku v morzeovce. Pre oba vzory použijeme poľa.

Štruktúra nášho programu by teraz mohla vyzerať nasledovne:

// reťazec, ktorý chceme dekódovať
let s = ".. - -. . - .-- --- .-. -.-"
print("Pôvodná správa: \(s)")
// reťazec s Dekódovanie správou
var zprava = ""

// vzorová pole
let abecedniZnaky = ["a", "b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
let morseovyZnaky = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
    "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
    "...-", ".--", "-..-", "-.--", "--.."]

Prečo je abeceda tiež ako pole? Ušetrí nám to veľa starostí pri hľadaní písmená podľa Morseova znaku. Inak by sme museli riešiť, ako rozumne previesť Array.Index na String.Index, a kód by bol oveľa dlhší.

Môžete si potom pridať ďalšie znaky ako čísla a interpunkčné znamienka, my ich tu vynecháme. Teraz si reťazec s rozbijeme metódou split() na pole podreťazcov, obsahujúcich jednotlivé znaky morzeovky. Splitová budeme podľa znaku medzery. Pole následne proiterujeme cyklom for..in:

// rozbitie reťazca na znaky morzeovky
let znaky = s.split(separator: " ")

// iterácie znaky morzeovky
for morseuvZnak in znaky {

}

Ideálne by sme sa mali nejako vysporiadať s prípadmi, kde užívateľ zadá napr. Viac medzier medzi znakmi (to užívatelia radi robia). split() potom vytvorí o jeden reťazec v poli viac, ktorý bude prázdny. Ten by sme mali potom v cykle detekovať a ignorovať, my sa s tým vo Swift tutoriálu nebudeme zaoberať.

V cykle sa pokúsime nájsť aktuálne čítaný znak morzeovky v poli morseovyZnaky. Bude nás zaujímať jeho index, pretože keď sa pozrieme na ten istý index v poli abecedniZnaky, bude tam zodpovedajúce písmeno. To je samozrejme z toho dôvodu, že obe polia obsahujú rovnaké znaky, zoradené podľa abecedy. Umiestni do tela cyklu nasledujúci kód:

let index = morseovyZnaky.index(of: String(morseuvZnak))

// Rozbalenie Optional, znak nájdený
if let index = index {
    zprava += abecedniZnaky[index]
}

Pokúsime sa zistiť index Morseova znaku. Ak sa to podarí, nájdeme v abecede zodpovedajúce písmeno a to pridáme do správy. Operátor += nahrádza zprava = zprava + abecedniZnak.

Záverom samozrejme správu vypíšeme:

print("Dekódovaná správa: \(zprava)")

výstup:

Pôvodná správa: .. - -. . - .-- --- .-. -.-
Dekódovaná správa: itnetwork

Hotovo! Za úlohu máte si naprogramovať program opačný, ktorý naopak zakóduje reťazec do morzeovky, kód bude veľmi podobný. Sa split() a joined() sa stretneme počas Swift kurzu ešte niekoľkokrát.

Špeciálne znaky alebo uvádzacích

Textový reťazec môže obsahovať špeciálne znaky, ktoré sú predsadené spätným lomítkom \. Je to najmä znak \n, ktorý kdekoľvek v texte spôsobí odriadkovanie a potom \t, kde sa jedná o tabulátor.

Poďme si to vyskúšať:

print("Prvý riadok\nDruhý riadok")

Znak \ označuje nejakú špeciálnu sekvenciu znakov v reťazci a je ďalej využívaný napr. K písanie unicode znaku ako \u{xxxx}, kde xxxx je kód znaku.

Problém môže nastať vo chvíli, keď chceme napísať samotné \, musíme ho tzv. Odescapovat:

print("Toto je spätné lomítko: \\")

Rovnakým spôsobom môžeme odescapovat napr. Úvodzovky tak, aby ju Swift nechápal ako koniec reťazca:

print("Toto je úvodzovky: \"")

Vstupy z konzoly a polí v okenných aplikáciách sa samozrejme escapují samy, aby užívateľ nemohol zadať \n a podobne. V kóde to má programátor povolené a musia na to myslieť.

Viacriadkový String

Swift 4 umožňuje definovať String na viac riadkov bez pridávania \n. Slúži na to trojité úvodzovky. Viacriadkový String sa deklaruje rovnako ako obyčajný String, po trojitých úvodzovkách ale musí nasledovať nový riadok. Uvniř môžete používať úvodzovky bez uvádzacích, takže sa to celé lepšie číta:

let dlouhyText = """
Takto môžete mať pekne dlhý text a zároveň
zachovať čitateľnosť alebo použiť &quot;úvodzovky&quot; ako chceme.
"""

print(dlouhyText)

Týmto sme v podstate zakončili sekcii sa základné štruktúrou jazyka Swift. V budúcej lekcii, Riešené úlohy k 9. lekcii Swift , si uvedieme bonusovú lekciu o viacrozmerných poliach a kurz ešte zakončuje ešte niečo o matematické triede. Zo základných konštrukcií jazyka vás tu ale už nič neprekvapí :) V podstate by ste už pokojne mohli ísť aj na objekty, odporúčajú ale zvyšné články ešte aspoň prejsť, jedná sa predsa len stále o základné znalosti, ktoré by ste mali mať.

V nasledujúcom cvičení, Riešené úlohy k 9. lekcii Swift, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 25x (33.33 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift

 

Predchádzajúci článok
Riešené úlohy k 8. lekcii Swift
Všetky články v sekcii
Základné konštrukcie jazyka Swift
Preskočiť článok
(neodporúčame)
Riešené úlohy k 9. lekcii Swift
Článok pre vás napísal Filip Němeček
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity