Lekce 10 - Textové řetězce v C# do třetice - Split a Join

C# .NET Základní konstrukce Textové řetězce v C# do třetice - Split a Join American English version English version

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V kurzu jsme si v minulé lekci, Textové řetězce v C# podruhé - práce s jednotlivými znaky, ukázali, že string je vlastně pole znaků. Dnes si vysvětlíme další metody na řetězci, které jsem vám záměrně zatajil, protože jsme nevěděli, že string je vlastně pole :)

Na řetězci můžeme používat mnoho metod, které známe z pole. Jsou to např: First(), Last(), IndexOf() a další.

Když si vytvoříme libovolnou proměnnou a napíšeme za ni tečku, Visual Studio nám zobrazí nabídku všech metod a vlastností (a také proměnných, ale k tomu se dostaneme až u objektů), které na ni můžeme volat. Tomuto nástroji se říká IntelliSense a zpříjemní nám práci s kódem, který za nás doplňuje. Zkusme si to:

Metody na textovém řetězci string ve Visual Studio

Tu samou nabídku lze vyvolat také stiskem CTRL + Mezerník v případě, že textový kurzor umístíme na tečku. Samozřejmě to platí pro všechny proměnné i třídy a budeme toho využívat stále častěji. Metody jsou řazené abecedně a můžeme jimi listovat pomocí kurzorových šipek. VS nám zobrazuje popis metod (co dělají) a jaké vyžadují parametry.

Řekněme si o následucících metodách a ukažme si je na jednoduchých příkladech:

Další metody na řetězci

Insert()

Vloží podřetězec do řetězce na určitou pozici. Parametry jsou pozice v řetězci a podřetězec.

Console.WriteLine("Já bych všechny ty internety zakázala.".Insert(29, "ne"));

Výstup:

Konzolová aplikace
Já bych všechny ty internety nezakázala.

Remove()

Vymaže znaky od dané pozice do konce. Parametrem je číselná pozice. Můžeme zadat druhý parametr, kterým je počet znaků, které chceme vymazat.

Console.WriteLine("Kdo se směje naposled, ten je admin.".Remove(12, 9));

Výstup:

Konzolová aplikace
Kdo se směje, ten je admin.

Substring()

Vrátí podřetězec od dané pozice do konce řetězce. Můžeme zadat druhý parametr, kterým je délka podřetězce.

Console.WriteLine("Kdo se směje naposled, ten je admin.".Substring(13, 8));

Výstup:

Konzolová aplikace
naposled

CompareTo()

Umožňuje porovnat dva řetězce podle abecedy. Vrací -1 pokud je první řetězec před řetězcem v parametru, 0 pokud jsou stejné a 1 pokud je za ním:

Console.WriteLine("akát".CompareTo("blýskavice"));

Výstup:

Konzolová aplikace
-1

Pojďme se nyní podívat na 2 další metody na stringu, které jsou opravdu velmi užitečné.

Split() a Join()

Z předchozího tutoriálu víme, že parsování řetězce po znaku může být někdy docela složité a to jsme dělali poměrně jednoduchý příklad. S řetězci se samozřejmě budeme setkávat stále, a to jak na vstupu od uživatele (např. z konzole nebo z polí v okenních aplikacích), tak v souborech TXT a XML. Velmi často máme zadán jeden delší string (řádek souboru nebo řádek konzole), ve kterém je více hodnot, oddělených tzv. separátory, např. čárkou. V tomto případě hovoříme o formátu CSV (Comma-Separated Values, tedy hodnoty oddělené čárkou). Abychom si byli jisti, že víme, o čem hovoříme, ukažme si nějaké ukázkové řetězce:

Jan,Novák,Dlouhá 10,Praha 3,130 00
.. ... .-.. .- -. -.. ... --- ..-. -
(1,2,3;4,5,6;7,8,9)
  • První řetězec je očividně nějaký uživatel, takto bychom mohli např. realizovat uložení uživatelů do CSV souboru, každý na jeden řádek.
  • Druhý řetězec jsou znaky Morseovy abecedy, separátor (oddělovač) je zde mezera.
  • Třetí řetězec je matice o 3 sloupcích a 3 řádcích. Oddělovač sloupců je čárka, řádků středník.

Na stringu můžeme volat metodu Split(), která bere jako parametr separátor (typu char), případně dokonce pole separátorů. Následně původní řetězec rozdělí podle separátorů na pole podřetězců, které vrátí. To nám velmi ulehčí práci při rozdělování hodnot v řetězci.

Metoda Join() se volá přímo na typu string a umožňuje nám naopak pole podřetězců spojit oddělovačem do jediného řetězce, parametry jsou oddělovač a pole. Výstupem metody je výsledný řetězec.

Jelikož neumíme tvořit objekty (uživatele) a ani pracovat s vícerozměrnými poli (matice), zkusíme si naprogramovat dekodér zpráv z Morseovy abecedy.

Dekodér Morseovy abecedy

Pojďme si opět připravit strukturu programu. Budeme potřebovat 2 řetězce se zprávou, jeden se zprávou v Morseově abecedě, druhý zatím prázdný, do kterého budeme ukládat výsledek našeho snažení. Dále budeme jako v případě samohlásek potřebovat nějaký vzor písmen. K písmenům samozřejmě vzor jejich znaku v morzeovce. Písmena můžeme opět uložit do pouhého stringu, protože mají jen jeden znak. Znaky Morseovy abecedy mají již znaků více, ty musíme dát do pole.

Struktura našeho programu by nyní mohla vypadat následovně:

// řetězec, který chceme dekódovat
string s = ".. - -. . - .-- --- .-. -.-";
Console.WriteLine("Původní zpráva: {0}", s);
// řetězec s dekódovanou zprávou
string zprava = "";

// vzorová pole
string abecedniZnaky = "abcdefghijklmnopqrstuvwxyz";
string[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};

Můžete si potom přidat další znaky jako čísla a interpunkční znaménka, my je zde vynecháme. Nyní si řetězec s rozbijeme metodou Split() na pole podřetězců, obsahujících jednotlivé znaky morzeovky. Splitovat budeme podle znaku mezery. Pole následně proiterujeme cyklem foreach:

// rozbití řetězce na znaky morzeovky
string[] znaky = s.Split(' ');

// iterace znaků morzeovky
foreach (string morseuvZnak in znaky)
{

}

Ideálně bychom se měli nějak vypořádat s případy, kde uživatel zadá např. více mezer mezi znaky (to uživatelé rádi dělají). Split() poté vytvoří o jeden řetězec v poli více, který bude prázdný. Ten bychom měli poté v cyklu detekovat a ignorovat, my se s tím v C# tutoriálu nebudeme zabývat.

V cyklu se pokusíme najít aktuálně čtený znak morzeovky v poli morseovyZnaky. Bude nás zajímat jeho index, protože když se podíváme na ten samý index v poli abecedniZnaky, bude tam odpovídající písmeno. To je samozřejmě z toho důvodu, že jak pole tak řetězec obsahují stejné znaky, seřazené dle abecedy. Umístěme do těla cyklu následující kód:

char abecedniZnak = '?';
int index = Array.IndexOf(morseovyZnaky, morseuvZnak);
if (index >= 0) // znak nalezen
    abecedniZnak = abecedniZnaky[index];
zprava += abecedniZnak;

Kód nejprve do abecedního znaku uloží '?', protože se může stát, že znak v naší sadě nemáme. Následně se pokusíme zjistit jeho index. Pokud se to podaří, dosadíme do abecedniZnak znak z abecedních znaků pod tímto indexem. Nakonec znak připojíme ke zprávě. Operátor += nahrazuje zprava = zprava + abecedniZnak.

Závěrem samozřejmě zprávu vypíšeme a přidáme ReadKey():

Console.WriteLine("Dekódovaná zpráva: {0}", zprava);
Console.ReadKey();

Konzolová aplikace
Původní zpráva: .. - -. . - .-- --- .-. -.-
Dekódovaná zpráva: itnetwork

Hotovo! Za úkol máte si naprogramovat program opačný, který naopak zakóduje řetězec do morzeovky, kód bude velmi podobný. Se Split() a Join() se potkáme během C# kurzu ještě několikrát.

Speciální znaky a escapování

Textový řetězec může obsahovat speciální znaky, které jsou předsazené zpětným lomítkem \. Je to zejména znak \n, který kdekoli v textu způsobí odřádkování a poté \t, kde se jedná o tabulátor.

Pojďme si to vyzkoušet:

Console.WriteLine("První řádka\nDruhá řádka");
Console.ReadKey();

Znak \ označuje nějakou speciální sekvenci znaků v řetězci a je dále využíván např. k psaní unicode znaku jako \uxxxx, kde xxxx je kód znaku.

Problém může nastat ve chvíli, když chceme napsat samotné \, musíme ho tzv. odescapovat:

Console.WriteLine("Toto je zpětné lomítko: \\");

Stejným způsobem můžeme odescapovat např. uvozovku tak, aby ji C# nechápal jako konec řetězce:

Console.WriteLine("Toto je uvozovka: \"");

Problém může být, když chceme zapsat nějakou delší cestu k souboru, kde máme velké množství zpětných lomítek. I na to v Microsoftu mysleli a zavedli modifikátor @, díky kterému C# automaticky escapuje celý námi napsaný řetězec v kódu:

Console.WriteLine(@"C:\Users\sdraco\Dropbox\itnetwork");

Vstupy z konzole a polí v okenních aplikacích se samozřejmě escapují sami, aby uživatel nemohl zadat \n a podobně. V kódu to má programátor povoleno a musí na to myslet.

Tímto jsme v podstatě zakončili sekci se základní strukturou jazyka C#. V příští lekci, Vícerozměrná pole v C# .NET, si uvedeme bonusový díl o vícerozměrných polích a sekci ještě zakončuje ještě něco o matematické třídě a pokročilém ovládání konzole. Ze základních konstrukcí jazyka vás tu ale již nic nepřekvapí :) V podstatě byste již klidně mohli jít i na objekty, doporučují ale zbylé články ještě alespoň projet, jedná se přeci jen stále o základní znalosti, které byste měli mít.


 

Stáhnout

Staženo 1009x (25.29 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
32 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (13)

 

 

Komentáře
Zobrazit starší komentáře (42)

Avatar
Marek Kaczmarczyk:23.5.2017 15:25

Moje zpetne zakodovani:

Editováno 23.5.2017 15:27
 
Odpovědět 23.5.2017 15:25
Avatar
Marek Kaczmarczyk:23.5.2017 15:26

Moje zpetne zakodovani:

Console.WriteLine("Dekodovana zprava : {0}: ", zprava);
Console.ReadKey();

string kodovani = "";

foreach(char c in zprava)
{
string morseuvZnak = "?";
int cislopismene = Array.IndexOf(abecedniZnaky.ToCharArray(), c);
if (cislopismene >= 0)//znak nalezen
morseuvZnak = morseovyZnaky[cislopismene];
kodovani += morseuvZnak+" | ";
}
Console.WriteLine("kodovani : {0}: ", kodovani);
Console.ReadKey();
 
Odpovědět 23.5.2017 15:26
Avatar
František Hejský:31.8.2017 20:16

Nejde to, jako převedený text do abecedy (naší) mi to ukáže otazník. Mam tam něco špatně? Koukněte:

string s = ".. - -. . - .-- --- .-. -.-";
            Console.WriteLine("Původní zpráva: {0}", s);

            string zprava = "";


            string abecedniZnaky = "abcdefghijklmnopqrstuvwxyz";
            string[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
            string[] znaky = s.Split(' ');


            foreach (string morseuvZnak in znaky)
            {

            }
            char abecedniZnak = '?';
            int index = Array.IndexOf(morseovyZnaky, morseuvZnak);
            if (index >= 0)
                abecedniZnak = abecedniZnaky[index];
            zprava += abecedniZnak;

            Console.WriteLine("Dekódovaná zpráva: {0}", zprava);
            Console.ReadKey();
 
Odpovědět 31.8.2017 20:16
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na František Hejský
David Čápka:31.8.2017 20:17

Špatně je už na první pohled ten prázdný cyklus :) V článku máš kód řešení, v příloze máš kód řešení. Oprav si to.

Odpovědět 31.8.2017 20:17
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
 
Odpovědět 31.8.2017 20:19
Avatar
Jirka Kouba
Člen
Avatar
Jirka Kouba:14. února 21:38

Mohl by mi někdo prosím vysvětlit funkci Substring() ? Z toho co se tu píše jsem moc nepochopil co se myslí tím podřetězcem.

 
Odpovědět 14. února 21:38
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Jirka Kouba
Martin Petrovaj:14. února 21:58

Podreťazec (angl. substring) je jednoducho časť pôvodného reťazca.

Príkaz Substring s jedným parametrom (celým číslom, indexom) funguje tak, že vezme pôvodný reťazec na ktorom ho voláš a vráti časť reťazca od daného indexu až po koniec reťazca. Napr. Substring na reťazci "Ahoj svet!" s parametrom 1 (štartovací index, od ktorého sa bude začínať nami chcený podreťazec) vráti podreťazec "hoj svet!".

S dvoma parametrami (index a dĺžka podreťazca, oba parametre celočíselné) funguje v podstate rovnako, len nevytvorí podreťazec od zadaného indexu až po koniec, ale zahrnie len nejakých x znakov (kde x je ten druhý parameter, ktorý sme práve pridali). Opäť, pre "Ahoj svet!" by s parametrami 1 (štartovací index) a 3 (dĺžka zostavovaného podreťazca) by Substring vrátil "hoj".

Ďalšie príklady v článku.

Odpovědět 14. února 21:58
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
Petr Zajac
Člen
Avatar
Odpovídá na Marek Kaczmarczyk
Petr Zajac:25. února 18:09

Netuším proč přiřazení "int cislopismene = Array.IndexOf(a­becedniZnaky.ToCha­rArray(), c);"
děláš opakovaně "rozsekání proměnné abecedníZnaky" na jednotlivá písena v cyklu na typ pole a nemáš to nad cyklem přiřazené do pole pojmenovaného např abeceda?

 
Odpovědět 25. února 18:09
Avatar
Dušan Kovářík:8. června 0:11

Kódování do Morseovy abecedy jsem udělal v podstatě jen úpravou kódu pro jeho dekódování. Místo cyklu

foreach

jsem použil

for

, v němž jsem si uložil Morseovy znaky kódované zprávy do prvků pole

string

ů, abych si mohl následně vyzkoušet metodu Join().

// řetězec, který chceme zakódovat
string zprava = "itnetwork";
Console.WriteLine("Původní zpráva: {0}", zprava);

// vzorová pole
string abecedniZnaky = "abcdefghijklmnopqrstuvwxyz";
string[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
    "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
    "...-", ".--", "-..-", "-.--", "--.."};

// pole znaků pro zakódovanou zprávu v morzeovce
string[] znaky = new string[zprava.Length];

// iterace abecedních znaků
int index;
for (int i = 0; i < zprava.Length; i++)
{
    znaky[i] = "?";
    index = abecedniZnaky.IndexOf(zprava[i]);
    if (index >= 0) // znak nalezen
        znaky[i] = morseovyZnaky[index];
}

// spojení pole znaků se zakódovanou zprávou do jednoho řetězce
string s = String.Join(" ", znaky);

Console.WriteLine("Zakódovaná zpráva: {0}", s);
Console.ReadKey();
 
Odpovědět 8. června 0:11
Avatar
Odpovídá na Dušan Kovářík
Dušan Kovářík:8. června 1:09

Omlouvám se za rozsekaný text na začátku před kódem :)

 
Odpovědět 8. června 1:09
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 52. Zobrazit vše