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:
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.
{SWIFT}
var text = "Ja by som všetky tie internety zakázala."
text.insert(contentsOf: "nie", at: text.index(text.startIndex, offsetBy: 29))
print(text)
{/SWIFT}
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.
{SWIFT}
var text = "Kto sa smeje naposledy, ten je admin."
text.remove(at: text.startIndex)
print(text)
{/SWIFT}
výstup:
do sa smeje naposledy, ten je admin.
A príklad na removeSubrange()
:
{SWIFT}
var text = "Kto sa smeje naposledy, ten je admin."
text.removeSubrange(text.index(text.startIndex, offsetBy: 3)..<text.endIndex)
print(text)
{/SWIFT}
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.
{SWIFT}
let text = "Kto sa smeje naposledy, ten je admin."
let endIndex = text.index(of: ",")!
let substring = String(text[...endIndex])
print(substring)
{/SWIFT}
výstup:
Kto sa smeje naposledy,
Skúsme si ďalší príklad:
{SWIFT}
let text = "Kto sa smeje naposledy, ten je admin."
let startIndex = text.index(of: ",")!
let substring = String(text[startIndex...])
print(substring)
{/SWIFT}
výstup:
, ten je admin.
A posledná:
{SWIFT}
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)
{/SWIFT}
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:
{SWIFT}
print("akát".compare("blýskavice").rawValue)
{/SWIFT}
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:
{SWIFT}
// 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 = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."]
let znaky = s.split(separator: " ")
// iterácie znakov morzeovky
for morseuvZnak in znaky {
let index = morseovyZnaky.index(of: String(morseuvZnak))
// Rozbalenie Optional, znak nájdený
if let index = index {
zprava += abecedniZnaky[index]
}
}
print("Dekódovaná správa: \(zprava)")
{/SWIFT}
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ť:
{SWIFT}
print("Prvý riadok\nDruhý riadok")
{/SWIFT}
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:
{SWIFT}
print("Toto je spätné lomítko: \\")
{/SWIFT}
Rovnakým spôsobom môžeme odescapovat napr. Úvodzovky tak, aby ju Swift nechápal ako koniec reťazca:
{SWIFT}
print("Toto je úvodzovky: \"")
{/SWIFT}
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ť "úvodzovky" 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