Jump to content
  • Announcements

    • Xmat

      Pravidlo pro postování v TTT

      Do sekce Tipy, triky, tutoriály nepatří žádné dotazy.   Postujte sem vaše návody, tipy a různé další věci jež uznáte za vhodné sdělit zdejšímu osazenstvu, ale veškeré dotazy směřujte do sekce Všeobecná diskuse.
    • Replik

      Seznam návodů a důležitých témat v této sekci

      Pro lepší přehlednost jsem vytvořil tento seznam, který vás, méně zkušené, lépe provede touto sekcí. Věřím, že zde najdete, co hledáte. Vypsané jsou návody, které jsou oficiálně uznané jako návody. Běžné diskuze, které neposkytují postupy a rady zvěřejněny nejsou.   Instalace vlastního MaNGOS Serveru Díky těmto návodům budete (měli by jste být) schopni vytvořit a následně spustit váš vlastní server. Nastavení je pro verze s i bez datadisku.   Instalace MaNGOS Serveru (bez datadisku TBC) - Autor Benny Instalace MaNGOS Serveru (s datadiskem TBC) - Autor Malfik Instalace MaNGOS Serveru v prostředí Linux - Autor charlie Instalace MaNGOS Serveru v prostředí Linux - Autor kupkoid   Chyby a jejich řešení při přihlašování k serveru - Autor Cybe   Zálohování uživatelských dat   Dávkový soubor (BAT soubor) pro vytvoření SQL záloh - Autor Replik   Kompilování - tvoření vlastních release (revizí)   Tvorba kompilací pro Win32 (MangoScript) - Autor bLuma   Ostatní - těžko zařaditelné, ale neznamená to, že nejsou dobré   VIP Systém - Autor charlie Tvorba Webových stránek pro MaNGOS - Autor zahuba Tvorba teleportačních NPC (MangoScript) - Autor Replik Registrační web (původně předělaná SPORA) Funkční pro Antrix i MaNGOS - Autor Replik Nastavení a spuštění Minimanager pro MaNGOS - Autor BlackMartin Nastavení MaNGOS Website - Autor Artorius   Samozřejmě jsou zde i jiné návody, ale tyto jsou nejvíce používané, proto věřím, že vám budou nápomocné. Tuto sekci budeme upravovat podle potřeby. Pokud by jste něco nenašli nebo si nevěděli rady, hledejte na fóru a teprve potom založte vlastní topik. Pokud nějaký autor vytvoří kvalitní návod a chtěl by ho zveřejnit i v tomto seznamu, doporučuji, aby mi napsal zprávu skrze PM.   Díky a přeji hezký den na WoWResource   Replik
    • Aristo

      Příspěvky tam, kde nemají co dělat

      Dodržujte zákaz přispívání do topiků s repaky pokud si to zakladatelé nepřejí!! Opakované psaní příspěvků bude trestáno warnem.
    • Aristo

      Používání spoilerů

      Poslední dobou má většina uživatelů fora zvláštní nutkání postovat extrémně dlouhé texty nebo kódy, které zabírají v nejedenom případu i 80% obsahu celé stránky a hodně tak zvedají nepřehlednost v topiku. Chtěl bych všechny uživatele požádat, aby při postování citací, jakýchkoliv kódů, errorů, atp... delších než 30 řádků používali funkci spoileru.   Funkci vyvoláte příkazem [spoiler] text [/spoiler]   Ukázka:  
Sign in to follow this  
Gelidus

[C++ Návod] Switchujeme stringy

Recommended Posts

Ahojte, nedávno som potreboval vo svojom programe switchovať stringy a myslím že sa to tu môže niekomu zísť tiež. Spravil som si teda pomocnú funkciu pre switch. Tu je:

 

String_Switch.cpp

 

 

int switch_strings(string f_param)
{
       const char *ch_strings[size_OF_STRINGS] = {"cls","exit"}; // medzi čím sa bude string switchovať ...
for(int i = 0; i < SIZE_OF_STRINGS; i++)
{
	if( f_param == ch_strings[i] )
	{
		return i;
	}
}
cout << "Switch not found";
return -1;
}

 

 

A takto by mala vyzerať funkcia Main :

 

 

#include "stdafx.h"
#include <iostream>
#include <string>
#include <string.h>

using namespace std;
#define SIZE_OF_STRINGS		2 // pokial potrebujete switchovať viac stringov, zmeníte aj definíciu

int switch_strings(string);

int _tmain(int argc, _TCHAR* argv[])
{
string param;
int i_param;
cin >> param;

i_param = switch_strings(param);
switch(i_param)
{
case 0:
	cout << "in function cls"; // sem patria už vaše funkcie
	break;
case 1:
	cout << "in function exit.";
	break;
}
system("pause");
return 0;
}

 

 

 

Vysvetlenie :

Uživatel zadá string, ktorý preberie funkcia switch_strings.

Tá prechádza cyklom for arrayom a až sa zhodujú, funkcia vráti jeho pozíciu v array.

Pozícia je využitá už pre switch hodnôt typu int.

 

Viem že to nie je nič svetoborné, ale snáď sa to niekomu zíde :)

 

Geli.

Edited by Gelidus
  • Upvote 1

Share this post


Link to post
Share on other sites

Chápu, že takto sice ,,vyřešíš" problém s tím, že v case nejde použít string, ale zapomínáš na co vlastně je switch určen. Rozdíl mezi switchem a vícenásobnýma podmínkama je přeci přehlednost a tvoje řešení na přehlednosti nepřidá, protože ve funkci sice máš deklarované nějaká klíčová slova která pak převádíš na case (a to pominu ztrátu znovupoužitelnosti takového řešení), ale ono použití bude úplně na jiném místě než definice funkce, tzn třeba v mainu budeš plácat case 0, 1.. ale pro ostatní to není přehledné.

 

+ ještě taková drobnost.. ve funkci nemá cout co dělat.. má návratovou hodnotu, tudíž nic víc netřeba.. to bys mohl tak možná v proceduře (rozuměj return void)

 

//edit typo

 

//edit2: abych jen nekritizoval, uměl bych si možná představit takové použití, ale definice těch klíčových slov (návazností na case) by se musela předávat parametrem té tvé funkci, pak by mohla padnout výtka o přehlednosti, protože by definice i použití mohlo být na jednom místě.. ale pořád je to takové škrábání levou rukou za pravým uchem :)

Edited by Filgron

Share this post


Link to post
Share on other sites

Díky za príspevky :). Viem, nie je to jediný spôsob ako na to. Chcel som hlavne veieť váš názor, popr. spôsob akým riešite tento problém.

 

Filgron : Pre mňa je to prehľadnejšie ako podmienky. Lepšie sa mi v tom orientuje ale to je môj názor ...

 

bLuma : Díky, hneď to idem skúsiť. Nad využitím pointerov som nerozmýšľal.

Share this post


Link to post
Share on other sites

Já jsem si to udělal trochu jinak. http://czshare.com/1762503/aTI1/console_menu_list.zip

 

Trochu jsem to zjednodušil. Zdroják:

 

/*******************************************************
* File:'Main.cpp'
* Win32 Console Menu
* copyright (c) 2011 Wolf Officious
*******************************************************/

#include <stdio.h>      // standart I/O
#include <conio.h>      // _getch()
#include <iostream>     // I/O streams
#include <string>       // string
#include <windows.h>    // GetStdHandle(), SetConsoleCursorPosition(), SetConsoleTextAttribute(), COORD, HANDLE ...

using namespace std;

#define MENU_BASE_X_POS             0   // Zakladni pozice X
#define MENU_BASE_Y_POS             7   // Zakladni pozice Y
#define MENU_ITEMS_COUNT            5   // Pocet polozek menu
#define MENU_COLOR_NORMAL           FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY // text: bila,   pozadi: cerna
#define MENU_COLOR_SELECTED         BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY // text: cerna,  pozadi: bila
#define DEFAULT_CONSOLE_COLOR       FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE                        // text: sediva, pozadi: cerna

enum menuItemDefs
{
   MENU_ITEM_0,
   MENU_ITEM_1,
   MENU_ITEM_2,
   MENU_ITEM_3,
   MENU_ITEM_EXIT
};

string GetMenuItemName(int index)
{
   if(index >= MENU_ITEMS_COUNT || index < NULL)
   {
       return "???";
   }

   static string menuItems[MENU_ITEMS_COUNT] =
   {
       "Položka 1",
       "Volba 2",
       "Možnost 3",
       "Výběr 4",
       "KONEC (esc)"
   };

   return menuItems[index];
}

int Menu()
{
   int selectedItem = 0;

   HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

   while(1)
   {
       for(int i = 0; i < MENU_ITEMS_COUNT; ++i)
       {
           COORD point;
           point.X = MENU_BASE_X_POS;
           point.Y = MENU_BASE_Y_POS + i;
           SetConsoleCursorPosition(hConsole, point);

           if(selectedItem == i)
           {
               SetConsoleTextAttribute(hConsole, MENU_COLOR_SELECTED);
               cout << " -> " << GetMenuItemName(i);
           }
           else
           {
               SetConsoleTextAttribute(hConsole, MENU_COLOR_NORMAL);
               cout << "    " << GetMenuItemName(i);
           }
       }

       cout << endl;

       switch(_getch())
       {
       case 72: // UP
           if(selectedItem > 0)
               --selectedItem;
           else
               selectedItem = MENU_ITEMS_COUNT - 1;
           continue;

       case 80: // DOWN
           if(selectedItem >= MENU_ITEMS_COUNT - 1)
               selectedItem = 0;
           else
               ++selectedItem;
           continue;

       case 0x0D:  // ENTER
           SetConsoleTextAttribute(hConsole, DEFAULT_CONSOLE_COLOR);
           return selectedItem;

       case 0x1B:  // ESCAPE
           SetConsoleTextAttribute(hConsole, DEFAULT_CONSOLE_COLOR);
           return MENU_ITEM_EXIT;

       default:
           continue;
       }
   }

   return -1;
}

int main(int argc, char **argv)
{
   // Default console color
   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), DEFAULT_CONSOLE_COLOR);

   // Czech locale support
   locale::global(locale("czech"));

   cout << " ******************************************************************************" << endl
        << " *                            <CONSOLE>  MENU LIST                            *" << endl
        << " ******************************************************************************" << endl
        << " (c)2011 Wolf Officious" << endl;

   int menuChoice = Menu();

   cout << endl
        << "Vybral jsi položku \"" << GetMenuItemName(menuChoice) << "\" (ID: " << menuChoice << ")" << endl;

   switch(menuChoice)
   {
   case MENU_ITEM_0:
       // TODO: insert code here
       break;

   case MENU_ITEM_1:
       // TODO: insert code here
       break;

   case MENU_ITEM_2:
       // TODO: insert code here
       break;

   case MENU_ITEM_3:
       // TODO: insert code here
       break;

   case MENU_ITEM_EXIT:
       cout << "Zazvonil zvonec a s programem je konec.. " << endl;
       break;

   default:
       cout << "Chybička se vloudila. " << endl;
       break;
   }

   cout << "Stiskni libovolnou klávesu..";
   (void)_getch();

   return 0;
}

 

 

EDIT: Je to celkem jednoduchý, ale jenom pro windows.

 

Definice jsou asi jasný, je tam pozice X a Y, počet položek a barvy.

Barvy se míchají z ?_RED, ?_GREEN, ?_BLUE a je možnost je "zvýraznit" pomocí ?_INTENSITY.

Místo otazníku dosazujeme buď FOREGROUND (popředí, nebo-li text) anebo BACKGROUND (pozadí).

 

Názvy položek jsou uvnitř funkce GetMenuItemName ve stringovým poli menuItems[], bacha na počet položek v definici MENU_ITEMS_COUNT.

enum menuItemDefs obsahuje "definice", které se pak používají v přepínači ( switch() { } ) uvnitř funkce main.

 

Funkce string GetMenuItemName(int index) vrací std::string na základě argumentu int index podle pole menuItems[].

Funkce int Menu() se stará o vykreslení menu, dále pak čeká na stisknutí správných kláves a navrací celočíselnou hodnotu volby.

V main funkci nastavíme výchozí barvu, "zlokalizujeme" konzoli do češtiny a zavoláme funkci Menu(), která nám vrátí číslo volby.

Dále je tam switch, jehož case odpovídají definicím v enum menuItemDefs.

 

Toť vše, vašnosto. :) Podobných snippetů mám hafo a k některým se rád vracím. :beach:

Edited by Wolf Officious
  • Upvote 2

Share this post


Link to post
Share on other sites

Vyžiadal si komentár. :mid_sword:

Čo ti ktomu povedať, ten "zjednodušený"kód je oveľa priehľadnejší ako ten prvý, takže sa to môže niekomu hodiť, ovšem nepíšeš najkrajšie, takže predpokladam že "pár" ľudí to nebude vedieť ani prečítať.

 

 

ps:trochu to viac rozpíš načo to slúži apod. //a v prvom príspevku to je, pardón)

Pps:´´možno sa to bude niekomu hodiť.

Edited by Valkyria

Share this post


Link to post
Share on other sites

Tím že jsem to "zjednodušil" jsem myslel zjednodušení oproti programu který jsem dal ke stažení na czshare.com.

Zkrátka je to menu v programu.. Šipkama nahoru/dolů se v menu pohybuje, enterem vybereš, esc to ukončí..

cml.png

 

Těžko bych to nějak blíž popisoval. Bude lepší, když si to každý vyzkouší sám.

console_menu_list.zip

  • Upvote 1

Share this post


Link to post
Share on other sites

Pěkná ukázka programu, který půjde zkompilovat a spustit jen pod operačním systémem od velkého Billa (což jsi zmínil), ale jaksi mi uniká důvod, proč jej bylo třeba zde publikovat celý, když smyslem tohoto topicu bylo, aspoň dle autora, zhodnocení jeho implementace určeného algoritmu a případné výtky/návrhy ke zlepšení. Ne že by nebyl poučný.., ale nestačila by jednoduchá ukázka? ;)

 

Mimoto i k tvé implementaci bych měl stejné výhrady jako u autorové. V definici si závislý na počtu položek v menu (define MENU_ITEMS_COUNT) a také používáš výčtový typ, kde jasně stanovuješ hodnoty, ale popisky k nim (pole menuItems) nastavuješ ve funkci, která by s tím neměla mít vůbec nic společného (cílem by přeci mělo být nastavovat hodnoty ideálně na jediném místě a ne na různých místech) -> klesá přehlednost a znovupoužitelnost pro kohokoliv jiného.

 

//edit typo^2

Edited by Filgron

Share this post


Link to post
Share on other sites

Tak jinak.. std::map je na klid, řekl bych:

/*******************************************************
* File:'Main.cpp'
* String Switch (map)
* copyright (c) 2011 Wolf Officious
*******************************************************/

#include <iostream>
#include <string>
#include <map>

int main(int argc, char **argv)
{
   static std::map<std::string, unsigned int> mValues;
   mValues["jedna"] = 1;
   mValues["dve"]   = 2;
   mValues["tri"]   = 3;
   mValues["ctyri"] = 4;

   std::string sInput;
   std::cout << "Input: ";
   std::cin >> sInput;

   switch(mValues[sInput])
   {
   case 1:
       std::cout << "1";
       break;

   case 2:
       std::cout << "2";
       break;

   case 3:
       std::cout << "3";
       break;

   case 4:
       std::cout << "4";
       break;

   case 0:
   default:
       std::cout << "Error - incorect input value.\n";
       break;
   }

   return 0;
}

 

Filgron: Tak taky něco hoď do placu, ne? Zatím jenom kibicuješ.

 

EDIT: spoiler

Edited by Wolf Officious

Share this post


Link to post
Share on other sites

Hulákadlo:

 

Wolf Officious: no pořát jenom kibicuje.. http://www.wowresource.eu/index.php?showtopic=23102&view=findpost&p=206332 (02 srpen 2011 - 02:30 )

Wolf Officious: kdyby tam hodil kód kterej je podle jeho představ, tak neřeknu ani putna.. ale to né, to je asi moc práce. (02 srpen 2011 - 02:32 )

 

Filgron: Tak taky něco hoď do placu, ne? Zatím jenom kibicuješ.

Pokud to bereš jako kibicování a ne jako dobře míněnou kritiku.. s tím nic nenadělám. Pokud ovšem vidíš na mých připomínkách něco neobjektivního, nebo dokonce nesmyslného, samozřejmě si rád vyslechnu připomínky, přeci jen nikdo není dokonalý.

 

K tomu proč nehodím něco do placu a dle tebe jen kibicuji. Autora jsem se v prvním příspěvku snažil navést, proč dle mne to řešení není ideální a jak by se dalo vylepšit, protože zastávám názor, že je lepší pokud se člověk sám snaží sebezdokonalovat a pochopit problematiku, sic při tom narazí na spoustu problémů, ale časem je vyřeší a do budoucna se jim vyvaruje, než aby se mu hodilo hotové řešení, které sice bude schopen nějak použít, ale spousta souvislostí mu unikne.

 

Ideální řešení (z mého pohledu) již zde navíc bylo postnuto bLumou (všechny nedostatky, které jsem na autorově řešení našel byly vyřešeny) i tvůj poslední post s využitím kontejneru to splňuje (rozdíl mezi těmi řešeními je pouze v eleganci - bLumův kód by šel použít i v obyčejném C, zatímco kontejnery jsou až v C++), tudíž podle mne opravdu není zapotřebí přispět dalším kouskem kódu, který by stejně v zásadě funkčně kopíroval tyto dvě výše zmíněné řešení.

 

//méně obsáhlá odpověď je i v historii hulákadla, žel bez diakritiky a s časovým odstupem..technika je zrádce :)

Share this post


Link to post
Share on other sites

Když je [C++ Návod] v názvu, tak proč řešíš že já používám std::map? Nicméně, ani bLuma tam nemá čistý Céčko (viz. std::cout). Jde o prkotinu, ale když už jsi to nakousnul... A když tu chceš psát něco o nějakém "kodexu" samouků, uvědom si že o to tady nejde. Mě by vážně zajímalo jak bys to řešil ty, když máš tolik výhrad. Těch způsobů totiž existuje plno a mohlo by to bejt zajímavý. Ale když se cukáš, tak si kuchni. :D

 

Když už jsme takhle odbočili, dovolím si poznamenat, že například programovací jazyk C# (Csharp) umí switchovat stringy úplně v klidu.

Share this post


Link to post
Share on other sites

Když je [C++ Návod] v názvu, tak proč řešíš že já používám std::map? Nicméně, ani bLuma tam nemá čistý Céčko (viz. std::cout).

 

Tady jde o použitelnost té funkce, ve stejném znění ji můžeš použít v C.

 

#include <stdio.h>
#include <string.h>
#include <process.h>

unsigned int chooseFrom(const char* input, const char** choices)
{
   const char** choice = choices;
   while (*choice)
   {
       if (!strcmp(input, *choice))
           return choice-choices;

       choice++;
   }

   return (unsigned int)-1;
}

int main()
{
   const char* inp = "abc";

   const char* choices[] =  {"baf", "abc", "holala", 0};
   switch (chooseFrom(inp, choices))
   {
       case 0: printf("baf\n"); break;
       case 1: printf("abc\n"); break;
       case 2: printf("holala\n"); break;
       default: printf("unkown\n"); break;

   }
   system("pause");
   return 0;
}

 

 

 

Ale tvé první řešení v první řadě neřeší obecnost problému výběru z řetězců. Omezuješ se na WinAPI a k tomu navíc konzolový interface. V mnoha případech může být nutné vybírat na základě textu v souboru nebo jinak neinteraktivně a tam je podobná omáčka nežádoucí.

 

Ad C#: Java donedávna také nepodporovala switch nad Stringem. V poslední verzi 7 tuto možnost přidali.

Share this post


Link to post
Share on other sites

Jasně, tak printf(const char * format, ...); je jasnej. A máš tam #include <process.h> úplně na nic.

Co se týče toho mýho prvního kódu, tam jsem chtěl demonstrovat jak jsem řešil "něco podobnýho" já.

Ten druhý kód je už lepší, mapy mám rád. A když tu jde o C++, nevidím důvod to tady řešit céčkově.

Edited by Wolf Officious

Share this post


Link to post
Share on other sites

A máš tam #include <process.h> úplně na nic.

 

Kód jde přeložit i bez toho, ale ne bez varování. Chybí pak deklarace pro funkci system (warning C4013: 'system' undefined; assuming extern returning int).

Share this post


Link to post
Share on other sites

Kód jde přeložit i bez toho, ale ne bez varování. Chybí pak deklarace pro funkci system (warning C4013: 'system' undefined; assuming extern returning int).

funkci system() (stejně jako exit() atd...) obsahuje stdlib.h

 

EDIT: viz. http://www.cplusplus.com/reference/clibrary/cstdlib/

Edited by Wolf Officious

Share this post


Link to post
Share on other sites

Process.h také i když není v ANSI C. Pod W32 platformou a některými dalšími je ten soubor dostupný. Pokud to jó chceš ANSI C tak si to přepiš. Ovšem tady nešlo o to v jakém je to hlavičkovém souboru. Ani o to rýpat se v tom, co je lepší pro C/C++. Vzhledem k lineární složitosti toho algoritmu by pro určité aplikace šlo vymyslet rychlejší varianty (binární půlení, hashování, ...). Což by bylo užitečnější než rýpat do těchto detailů.

Share this post


Link to post
Share on other sites

O binárním půlení vím kulový. :ermm: Hashování mě taky napadlo, ale to by bylo možná už příliš a hashování už samo o sobě může bejt jistá "decentní" brzda. Těžko říct, asi záleží na konkrétním použití. Takovej kód by mě třeba hodně zajímal.

 

EDIT: Jako další možnost, by se možná dala využít funkce find u stringů.

 

EDIT2: Počkej, binární půlení se používá třeba u mangosu na různý flagy atd.., žejo?

Edited by Wolf Officious

Share this post


Link to post
Share on other sites

Sorry za oživení, ale prohrabal jsem svoje starší kódy z minulého roku a napadlo mě, že by se Vám mohlo hodit moje (ehm.. "nové") řešení. :) Tohle řešení spočívá ve třech makrech a dvou definicích. V podstatě je to sekvence if/else.

#define SWITCH_OPEN(input)          { const char * __switch_string__ = input;
#define SWITCH_CASE_FIRST(value)    if(__switch_string__ == value) {
#define SWITCH_CASE(value)          } else if(__switch_string__ == value) {
#define SWITCH_DEFAULT              } else {
#define SWITCH_CLOSE                }}

 

Příklad použití:

   SWITCH_OPEN("text ktery hledam")
       SWITCH_CASE_FIRST("text co je mi fuk")
           cout << "1\n";
       SWITCH_CASE("text ktery hledam")
           cout << "2\n";
       SWITCH_CASE("dalsi z textu, ktery me nazajima")
           cout << "3\n";
       SWITCH_DEFAULT
           cout << "default\n";
   SWITCH_CLOSE;

Takto vytvořený "náhradní" switch má však jeden obrovský háček. Jeho case se automaticky lámou (což je logické, když v podstatě končí vnoření), takže když potřebujeme vyvolat stejnou sekvenci kódu ve více než jednom případě, museli bychom ho opisovat pro každý případ (case) zvlášť.

 

Vím že ještě existují způsoby, které využívají initializer_list nebo fastmatch, ale taky nic moc. Navíc u nich většinou musí být hodnoty seřazené podle abecedy, což je také svazující. Žádný z nich stejně neumí obejít ten problém s nuceným lámáním případů. Až tedy na hash, ale to (podle mého názoru) trochu ztrácí na eleganci. :tomato:

 

Doufám že to pomůže. Znáte někdo lepší řešení? :):beach:

Edited by Wolf Officious

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

×