7. díl - Ošetření uživatelských vstupů

C# .NET Základní konstrukce Ošetření uživatelských vstupů American English version English version

Minule jsme se zabývali cykly . Dnes to bude takové oddechové, dokončíme si totiž naši kalkulačku, dále už ji nebudeme potřebovat a bylo by hezké ji dotahnout do konce. Asi tušíte, že u ni chybí zabezpečení vstupů od uživatele, tím se bude zabývat dnešní tutoriál.

Připomeňme si kód naší kalkulačky:

Console.WriteLine("Vítejte v kalkulačce");
string pokracovat = "ano";
while (pokracovat == "ano")
{
        Console.WriteLine("Zadejte první číslo:");
        float a = float.Parse(Console.ReadLine());
        Console.WriteLine("Zadejte druhé číslo:");
        float b = float.Parse(Console.ReadLine());
        Console.WriteLine("Zvolte si operaci:");
        Console.WriteLine("1 - sčítání");
        Console.WriteLine("2 - odčítání");
        Console.WriteLine("3 - násobení");
        Console.WriteLine("4 - dělení");
        int volba = int.Parse(Console.ReadLine());
        float vysledek = 0;
        switch (volba)
        {
                case 1:
                        vysledek = a + b;
                break;
                case 2:
                        vysledek = a - b;
                break;
                case 3:
                        vysledek = a * b;
                break;
                case 4:
                        vysledek = a / b;
                break;
        }
        if ((volba > 0) && (volba < 5))
                Console.WriteLine("Výsledek: {0}", vysledek);
        else
                Console.WriteLine("Neplatná volba");
        Console.WriteLine("Přejete si zadat další příklad? [ano/ne]");
        pokracovat = Console.ReadLine();
}
Console.WriteLine("Děkuji za použití kalkulačky, aplikaci ukončíte libovolnou klávesou.");
Console.ReadKey();

Už jsme si jednou říkali, že bychom měli vstupy od uživatele vždy ošetřovat. Řeknu vám tajemství úspěšných a oblíbených aplikací, je velmi jednoduché: Počítají s tím, že je uživatel naprostý hlupák :) Čím hloupějšího uživatele budete předpokládat, tím větší úspěch budou vaše aplikace mít. Pokud zde uživatel zadá místo "ano" např. "ano " (ano mezera) nebo "Ano" (s velkým písmenem), program stejně skončí. To ještě nemusí být kvůli hlouposti, ale proto, že se překlepl. Může nám však zadat i něco úplně nesmyslného, např. "možná".

To není však největší problém našeho programu, když uživatel nezadá číslo, ale nějaký nesmysl, celý program se zastaví a spadne s chybou. Pojďme nyní tyto dva problémy opravit.

K ověření správnosti vstupu při jeho parsování můžeme místo metody Parse použít metodu TryParse. Metoda vrací true/false podle toho, jestli se parsování podařilo či nikoli. Jestli se ptáte, jak z metody tedy dostaneme naparsovanou hodnotu, tak ta se nám uloží do proměnné předané druhým parametrem. U parametru musíme uvést modifikátor out, zatím se jím nebudeme zatěžovat, budeme brát jako fakt, že to metoda TryParse takhle má. Hodnota proměnné, kterou jsme takto předali do druhého parametru bude ovlivněna. Ukážeme si to u prvního čísla, u druhého to bude samozřejmě analogické a jen to opíšeme. Ideálně bychom si na to měli vytvořit metodu, abychom nepsali 2x ten samý kód, ale zatím není vhodná doba se tímto zabývat, metody se naučíme definovat až u objektově orientovaného programování.

Console.WriteLine("Zadejte první číslo:");
float a;
while (!float.TryParse(Console.ReadLine(), out a))
        Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");

Na kódu není nic složitého. Nejprve vyzveme uživatele k zadání čísla a deklarujeme proměnnou a. Následně přímo do podmínky while cyklu vložíme TryParse, podmínku znegujeme operátorem "!", tedy dokud vrací false, bude se cyklus stále opakovat a vyzývat k novému zadání. Zadaný text z konzole se naparsuje do proměnné a je navráceno true, pokud se parsování nepovede, je vráceno false.

Nyní se ještě podíváme na výběr operace a pokračování. Obě volby načítáme jako string i když to není úplně vhodné. U čísel to má opodstatnění, protože mohou mít délku větší než jeden znak a musí být odenterovány. U volby operací 1-4 ale vůbec nepotřebujeme načítat text a potvrzovat ho enterem, stačí načíst jediný znak z klávesnice a ten nemusíme ničím potvrzovat. K načtení jediného znaku slouží nám již známá metoda Console.ReadKey(). Abychom výsledek dostali jako char (znak), musíme na této metodě použít vlastnost KeyChar. Ve switchi nezapomínejme, že char se zapisuje do apostrofů.

char volba = Console.ReadKey().KeyChar;
float vysledek = 0;
bool platnaVolba = true;
switch (volba)
{
        case '1':
                vysledek = a + b;
                break;
        case '2':
                vysledek = a - b;
                break;
        case '3':
                vysledek = a * b;
                break;
        case '4':
                vysledek = a / b;
                break;
        default:
                platnaVolba = false;
                break;
}
if (platnaVolba)
        Console.WriteLine("Výsledek: {0}", vysledek);
else
        Console.WriteLine("Neplatná volba");

Do proměnné volba si uložíme stisknutý znak jako char. Protože rozsah znaků neotestujeme s dosavadními znalostmi tak jednoduše jako rozsah čísel, pomůžeme si jiným způsobem. Připravíme si proměnnou platnaVolba typu bool, kterou nastavíme na true (budeme předpokládat, že je volba správná). Switch zůstane podobný, jen čísla dáme nyní do apostrofů, protože se nyní jedná o jednotlivé znaky. Přidáme možnost default, která v případě jiné hodnoty než jmenovaných nastaví námi připravenou proměnnou platnaVolba na false. Potom není nic jednoduššího, než tuto proměnnou otestovat. Vyzkoušejte si to, program se používá nyní pohodlněji.

Nakonec upravíme ještě výzvu k pokračování, zadávat budeme opět char A/N, budeme tolerovat různou velikost písmen a reagovat na špatné zadání. Opět použijeme switch, naši proměnnou pokracovat změníme na typ bool. Kód je asi zbytečné více popisovat, za zmínku stojí pouze kombo Console.ReadKe­y().KeyChar.ToS­tring().ToLower(), které načte znak z konzole a vrátí ho jako string malými písmeny.

Protože se jedná o větší kus kódu, použijeme tzv. komentáře. Ty s píší pomocí dvoulomítka (dvou lomítek za sebou). Jsou to informace pro programátora, kompilátor si jich nevšímá.

Console.WriteLine("Vítejte v kalkulačce");
bool pokracovat = true;
while (pokracovat)
{
        // načtení čísel
        Console.WriteLine("Zadejte první číslo:");
        float a;
        while (!float.TryParse(Console.ReadLine(), out a))
                Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");
        Console.WriteLine("Zadejte druhé číslo:");
        float b;
        while (!float.TryParse(Console.ReadLine(), out b))
                Console.WriteLine("Neplatné číslo, zadejte prosím znovu:");
        // volba operace a výpočet
        Console.WriteLine("Zvolte si operaci:");
        Console.WriteLine("1 - sčítání");
        Console.WriteLine("2 - odčítání");
        Console.WriteLine("3 - násobení");
        Console.WriteLine("4 - dělení");
        char volba = Console.ReadKey().KeyChar;
        Console.WriteLine();
        float vysledek = 0;
        bool platnaVolba = true;
        switch (volba)
        {
                case '1':
                        vysledek = a + b;
                        break;
                case '2':
                        vysledek = a - b;
                        break;
                case '3':
                        vysledek = a * b;
                        break;
                case '4':
                        vysledek = a / b;
                        break;
                default:
                        platnaVolba = false;
                        break;
        }
        if (platnaVolba)
                Console.WriteLine("Výsledek: {0}", vysledek);
        else
                Console.WriteLine("Neplatná volba");
        Console.WriteLine("Přejete si zadat další příklad? [a/n]");
        // dotaz na pokračování
        platnaVolba = false;
        while (!platnaVolba)
        {
                switch (Console.ReadKey().KeyChar.ToString().ToLower())
                {
                        case "a":
                                pokracovat = true;
                                platnaVolba = true;
                        break;
                        case "n":
                                pokracovat = false;
                                platnaVolba = true;
                        break;
                        default:
                                Console.WriteLine("Neplatná volba, zadejte prosím a/n");
                        break;
                }
        }
        Console.WriteLine();
}
Jednoduchá konzolová kalkulačka v C# s ošetřením vstupů

Gratuluji, právě jste vytvořili svůj první blbovzdorný program :) Kód se nám trochu zkomplikoval, snad jste to všechno pochytili. Někdy v budoucnu to třeba napravíme a rozdělíme ho do přehledných metod, pro tuto sekci však považujme kalkulačku za hotovou, možná by se do ní jen mohlo přidat více matematických funkcí, na ty se v seriálu také zaměříme.

Příště se opět ponoříme do nových konstrukcí, čeká nás pole a pokročilá práce s řetězci. Potom to bude z konstrukcí v této sekci vše, blížíme se ke konci :)


 

Stáhnout

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

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (30 hlasů) :
4.966674.966674.966674.966674.96667


 


Miniatura
Předchozí článek
Cvičení k 6. lekci C# .NET
Miniatura
Všechny články v sekci
Základní konstrukce jazyka C#
Miniatura
Následující článek
Pole v C#

 

 

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

Avatar
Ondřej Štorc:

Převedený na string je to z důvodu konverze toho písmena na malý. U charu to taky jde a to pomocí funkce char.ToLower(), ale Davidovi nejspíše přišla tahle varianta přehlednější než to celé zabalovat do závorek :)

Odpovědět  +1 17.3.2015 22:15
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Odpovídá na Ondřej Štorc
Matěj Prášek:

Děkuji :-) Nenapadlo mě, že u charu nepůjde použít metoda ToLower() stejně jako u stringu. Teď vím zase o něco víc :-)

 
Odpovědět 17.3.2015 22:40
Avatar
dleducmanh6
Člen
Avatar
dleducmanh6:

Ahoj, sestrojil jsem program vypočítávající S trojúhelníku a mám s jedním detailem problém. Na začátku programu si mám napsat kolikrát se mi S vypíše, vypočítat S, a součet obsahů (kolikrát se mi vypíšou tolikrát je vynásobím). Pointa je, že se mi má POUZE S vypsat kolikrát si to vyžádám součet S a kolikrát jsem si to vyžádal ne. :/
Console.Write­Line("Zadej délku strany a výšku na zadanou stranu a vypočítám ti obsah");
int Va = int.Parse (Console.ReadLine ());
int strana_a = int.Parse (Console.ReadLine ());
int děleno = 2;
Console.WriteLine ("Zadej kolikrát chceš abych ti vypsal obsah: ");
int ntá = int.Parse (Console.ReadLine ());
for (int i=0; i < ntá; i++)
{
int S = Va * strana_a / děleno;
Console.WriteLine ("Velikost obsahu je {0} cm čtverečních ", S);
Console.WriteLine ("Obsah jsem ti vypsal {0}krát.", ntá);
int součet_S = S * ntá;
Console.WriteLine ("Součet obsahů je {0}.", součet_S);
}
Console.ReadLine ();

 
Odpovědět 23.12.2015 19:17
Avatar
Miroslav Křenek:

Pokud by se volba na pokračování nenačetla jako string, ale jako char, tak by to šlo třeba takto:

while (!platnaVolba)
                {
                    char an = char.ToLower(Console.ReadKey().KeyChar);
                    switch (an)
                    {
                        case 'a':
                            pokracovat = true;
                            platnaVolba = true;
                            break;
                        case 'n':
                            pokracovat = false;
                            platnaVolba = true;
                            break;
                        default:
                            Console.WriteLine("Neplatná volba, zadejte prosím a/n");
                            break;
                    }
                }
 
Odpovědět 16. května 0:58
Avatar
Pavla Sklenářová:

Ahoj, mohli byste mi prosím **polopatě **vysvětlit, jak přesně funguje ten blbuvzdorný (vzdoruje mi to skutečně úspěšně) dotaz na pokračování? Vytvořila jsem si jakous takous šablonu,tak pro inteligentního uživatele to normálně funguje, ale když zadám za sebou 2x neplatnou volbu, program se mi spustí od počátku, místo aby mi pořád házel hlášku "Zkuste to znovu." Vím, že už se to tady jednou řešilo, ale nebyla jsem z toho moc moudrá. Zřejmě mi unikl nějaký základ. Vím, že bych místo bool pokracovat mohla prostě použít string pokracovat a dát tomu hodnotu "ano", ale chci to pochopit. Děkuju moc za snahu. Přikládám kód.

static void Main(string[] args)
       {
           bool pokracovat = true; //Předpokládám, že budu chtít pokračovat. Switch mě hodí sem a srovná svoje hodnoty s touto výchozí.

           while (pokracovat)
           {

               Console.WriteLine("Tady něco dělám a budu to opakovat, dokud si to bfu žádá.");
               Console.WriteLine("Pro pokračování stiskněte A, pro ukončení stiskněte N.");

               string volba = Console.ReadLine().ToLower();
               //načti vstup. v případě, že vstup je a, cyklus bude pokračovat, v případě n nebude.
               //break mě vyhodí sem, musím case porovnat s uživatelským vstupem, nikoliv s pevnou hodnotou.

               switch (volba)
                   {
                       case "a":

                           pokracovat = true;


                           break;

                       case "n":

                           pokracovat = false;

                           Console.WriteLine("Končíme.");
                           Console.ReadLine();

                           break;

                       default:
                           // při pokračovat - true mi najede program, při false mi skončí.

                           Console.WriteLine("Zkuste to znovu. A/N");
                           Console.ReadLine();

                           break;
                   }


            }

           }
Odpovědět 29. května 17:34
Nepropadejte panice.
Avatar
Petr Stastny
Redaktor
Avatar
Odpovídá na Pavla Sklenářová
Petr Stastny:

Mozna z defaultu odstranit ten radek Console.ReadLi­ne();? Nezkousel jsem to, ale snad to pomuze

Editováno 30. května 20:41
 
Odpovědět 30. května 20:41
Avatar
Odpovídá na Petr Stastny
Pavla Sklenářová:

Nepomůže. Akorát mě to vrátí zpět na while a jede to znova celé, místo aby se mi zopakovala chybová hláška.

Odpovědět 30. května 22:19
Nepropadejte panice.
Avatar
Roman Šimík:

No pokud nechce, aby se stisknuté klávesy vypisovali, tak by měl nastavit hodnotu na true

ReadKey(true)

Jelikož je to defaultně nastavené na false, tudíž když by tam dal false tak by se nic nestalo.

 
Odpovědět  +1 19. června 11:00
Avatar
Odpovídá na Pavla Sklenářová
Roman Šimík:

Musíš si vytvořit ještě jednu boolean, která ti řekne, zda bylo zmáčknuto "a" a "n" a nebo nějaká jiná klávesa, a pote přidat podmínku while, která řekne že pokud je ta boolean false, tak se znovu zeptá.na nový stisk klávesy

static void Main(string[] args)
        {
            bool pokracovat = true; //Předpokládám, že budu chtít pokračovat. Switch mě hodí sem a srovná svoje hodnoty s touto výchozí.

            while (pokracovat)
            {

                Console.WriteLine("Tady něco dělám a budu to opakovat, dokud si to bfu žádá.");
                Console.WriteLine("Pro pokračování stiskněte A, pro ukončení stiskněte N.");

                //načti vstup. v případě, že vstup je a, cyklus bude pokračovat, v případě n nebude.
                //break mě vyhodí sem, musím case porovnat s uživatelským vstupem, nikoliv s pevnou hodnotou.

                bool spravnaVolba = false; // vytvoření bool, předpokládáme že je false

                while (!spravnaVolba) // Pokud je hodnota spravne volby false, tak...
                {
                    string volba = Console.ReadLine().ToLower(); // Uložení stisknuté klávesy musíme dát do while podmínky, protože pokud by jsme tak neudělali, tak by byla uložená jen jedna a ta samá hodnota
                    switch (volba)
                    {
                        case "a":
                            spravnaVolba = true; // správná volba, nastavíme proto hodnotu na true
                            pokracovat = true;


                            break;

                        case "n":
                            spravnaVolba = true; // správná volba, nastavíme proto hodnotu na true
                            pokracovat = false;

                            Console.WriteLine("Končíme.");
                            Console.ReadLine();

                            break;

                        default:
                            // při pokračovat - true mi najede program, při false mi skončí.
                            spravnaVolba = false; // nesprávná volba, nastavíme proto hodnotu na false
                            Console.WriteLine("Zkuste to znovu. A/N");
                            Console.ReadLine();

                            break;
                    }
                }


            }

        }
Editováno 19. června 11:18
 
Odpovědět  +1 19. června 11:16
Avatar
Odpovědět 19. června 13:44
Nepropadejte panice.
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 63. Zobrazit vše