Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

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.

Klikni pre editáciu
  • var text = "Ja by som všetky tie internety zakázala."
    text.insert(contentsOf: "nie", at: text.index(text.startIndex, offsetBy: 29))
    print(text)
    
    • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

    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.

    Klikni pre editáciu
    • var text = "Kto sa smeje naposledy, ten je admin."
      text.remove(at: text.startIndex)
      print(text)
      
      • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

      výstup:

      do sa smeje naposledy, ten je admin.

      A príklad na removeSubrange():

      Klikni pre editáciu
      • var text = "Kto sa smeje naposledy, ten je admin."
        text.removeSubrange(text.index(text.startIndex, offsetBy: 3)..<text.endIndex)
        print(text)
        
        • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

        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.

        Klikni pre editáciu
        • let text = "Kto sa smeje naposledy, ten je admin."
          let endIndex = text.index(of: ",")!
          let substring = String(text[...endIndex])
          print(substring)
          
          • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

          výstup:

          Kto sa smeje naposledy,

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

          Klikni pre editáciu
          • let text = "Kto sa smeje naposledy, ten je admin."
            let startIndex = text.index(of: ",")!
            let substring = String(text[startIndex...])
            print(substring)
            
            • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

            výstup:

            , ten je admin.

            A posledná:

            Klikni pre editáciu
            • 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)
              
              • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

              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:

              Klikni pre editáciu
              • print("akát".compare("blýskavice").rawValue)
                
                • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                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:

                Klikni pre editáciu
                • print("Dekódovaná správa: \(zprava)")
                  
                  • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                  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ť:

                  Klikni pre editáciu
                  • print("Prvý riadok\nDruhý riadok")
                    
                    • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                    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:

                    Klikni pre editáciu
                    • print("Toto je spätné lomítko: \\")
                      
                      • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

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

                      Klikni pre editáciu
                      • print("Toto je úvodzovky: \"")
                        
                        • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                        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

                         

                        Ako sa ti páči článok?
                        Pred uložením hodnotenia, popíš prosím autorovi, čo je zleZnakov 0 z 50-500
                        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