Indice pour réussir
Fermé
ik
-
Modifié le 25 août 2018 à 22:00
mamiemando
mamiemando
- Messages postés
- 31324
- Date d'inscription
- jeudi 12 mai 2005
- Statut
- Modérateur
- Dernière intervention
- 19 août 2022
A voir également:
- Indice pour réussir
- Indice latex ✓ - Forum - Astuces et Solutions
- L'indice n'appartient pas à la sélection vba - Forum - VB / VBA
- Dédouanement reussi aliexpress ✓ - Forum - Consommation et internet
- Winword.exe l'application n'a pas réussi à démarrer correctement ✓ - Forum - Windows 10
- Indice telephonique france - Guide
1 réponse
mamiemando
Modifié le 15 sept. 2018 à 18:20
- Messages postés
- 31324
- Date d'inscription
- jeudi 12 mai 2005
- Statut
- Modérateur
- Dernière intervention
- 19 août 2022
Modifié le 15 sept. 2018 à 18:20
Bonjour,
Ça me paraît bien (même si je n'ai pas pu tester le programme étant donné que je ne sais pas ce que dois contenir le fichier lu).
Voici ton code modifié (même si personnellement j'aurais choisi un autre format de fichier.)
cle.txt
transform.cpp
Compilation
Exécution
Résultat
Quelques conseils / remarques par rapport à ton code
Bonne chance
Ça me paraît bien (même si je n'ai pas pu tester le programme étant donné que je ne sais pas ce que dois contenir le fichier lu).
Voici ton code modifié (même si personnellement j'aurais choisi un autre format de fichier.)
cle.txt
AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYy
transform.cpp
#include <algorithm> // std::transform #include <cstdlib> // EXIT_* #include <iostream> // std::cout, std::cerr #include <fstream> // std::ifstream #include <ostream> // std::ostream #include <map> // std::map #include <string> // std::string #define DEFAULT_INPUT_TEXT "BIENVENUE SUR LE MOOC C++ D'OCR !!" /** * @brief Traduit une std::map au format input_text. * @param os Le flux de sortie. * @param m La std::map à traduire. * @param os Le flux de sortie modifié. */ template <typename K, typename V> std::ostream & operator << (std::ostream & os, std::map<K,V> m) { os << '{'; for (auto p : m) { os << '\t' << p.first << " : " << p.second << std::endl; } os << '}'; return os; } /** * @brief Lit un fichier et associe dans une std::map le 2*i ème caractère * au 2*i+1 ème caractère, 0 <= i <= 26. * @brief Le chemin vers le fichier à lire. * @param La std::map à compléter. * @return true en cas de succès, false sinon. */ bool parse_key_file(const std::string & filename, std::map<char, char> & table) { bool ret = true; char lettre, substitut; std::ifstream fichier(filename); if (fichier) { for(int i = 0; i < 26; ++i) { fichier >> lettre >> substitut; table[lettre] = substitut; } } else { std::cerr << "Nom de fichier [" << filename << "] invalide" << std::endl; ret = false; } return ret; } /** * @brief Foncteur qui effectue un chiffrement par decalage */ class ChiffrementSubst{ private: std::map<char, char> m_table; /**< La table contenant les caracteres cryptes. */ public: /** * @brief Constructeur. * @param Chemin absolu du fichier contenant les decalages à utiliser. */ ChiffrementSubst(const std::map<char, char> & table): m_table(table) {} /** * @brief Traduit une lettre vers la lettre chiffrée. * @param lettre La lettre à chiffrer. * @return La lettre chiffrée. */ inline char operator()(char lettre) const { std::map<char, char>::const_iterator fit(m_table.find(lettre)); return fit != m_table.end() ? fit->second : '?'; } }; /** * @brief Programme principal. * @param argc Nombre d'arguments. * @param argv Arguments reçus en paramètres. */ int main(int argc, char ** argv) { if (argc >= 4) { std::cerr << "usage: " << argv[0] << " [filename [input_text]]" << std::endl; return EXIT_FAILURE; } // Demande du décalage à l'utilisateur std::string filename; if (argc >= 2) { filename = argv[1]; } else { std::cout << "Quel fichier contenant la clé voulez-vous utiliser ? "; std::cin >> filename; } // Préparation du message à crypter std::string input_text = argc >= 3 ? argv[2] : DEFAULT_INPUT_TEXT; std::cout << "input_text = '" << input_text << "'" << std::endl; // Lecture du fichier d'entrée std::map<char, char> table; bool success = parse_key_file(filename, table); if (!success) { std::cerr << "Fichier d'entrée incorrect [" << filename << "]" << std::endl; return EXIT_FAILURE; } // DEBUG //std::cout << table << std::endl; // Création du foncteur ChiffrementSubst fonctor(table); // Chaine de caracteres pour le message chiffre std::string output_text; output_text.resize(input_text.size()); // Un iterateur permettant l'insertion a la fin std::transform(input_text.begin(), input_text.end(), output_text.begin(), fonctor); std::cout << "output_text = '" << output_text << "'" << std::endl; return EXIT_SUCCESS; }
Compilation
g++ -W -O2 transform.cpp -o transform
Exécution
./transform cle.txt BONJOUR
Résultat
input_text = 'BONJOUR'
output_text = 'bonjour'
Quelques conseils / remarques par rapport à ton code
- Personnellement, je recommande au début de ne pas utiliser
using namespace std;
. Certes ça allège grandement l'écriture, mais il faut garder que ce genre d'instruction est à proscrire dans header (fichier .hpp). Certes ici on est dans un fichier source (.cpp) mais c'est pas mal au début de se graver dans l'esprit qui est dans quel namespace. En effet, ça prépare le terrain pour la suite quand on fait de la méta programmation (cf template) ou quand on utilise des objets provenant de différents namespace (e.g.std::
,boost::
, etc.). Mais ce que tu as écrit est parfaitement correct et légitime. - Pas besoin de recopier la chaîne
output_text
pour l'afficher, tu peux l'utiliser directement. Ça économisera une recopie qui n'apporte rien dans ton cas. Pourstd::ifstream ifs(filename.c_str())
, pas besoin de convertir le chemin destd::string
versconst char *
. - Pour bénéficier des générateurs de documentations (e.g. doxygen) tu peux documenter tes fonctions/méthodes/classe comme indiqué ci-dessus.
- En terme de design, la partie foncteur et lecture du fichier sont deux considérations indépendantes. En découplant les deux, comme je l'ai fait, tu te laisses possibilité d'obtenir
table
autrement (lecture surstd::cin
, à partir d'un autre parser, par exemple un fichier json, etc...) - Il est préférable d'obtenir les paramètres du programme (dans ton cas, le chemin du fichier clé
filename
et le texte d'entréeinput_text
) via les arguments du programme que viastd::cin
: cela permet de faciliter l'intégration de ton programme dans un autre programme (e.g. un script). - Attention à bien contrôler les cas d'erreur (chemin invalide, etc...) et à interrompre ton programme quand cela arrive. Une manière de faire est aussi de lever des exceptions (exemple :
throw std::runtime_error("Erreur");
) - Il vaut mieux prendre l'habitude de nommer ses variables en anglais plutôt qu'en français. Car dans la vraie vie, nos coéquipiers développeurs ne sont pas toujours français !
- Si on pousse le truc à l'extrême (ce que je ne fais pas en temps normal), on peut définir les messages dans des
#define
, ce qui permet de les modifier à la compilation et d'envisager un programme en plusieurs langues, typiquement avec l'option -D si tu utilisesg++
! - On évite les "pause" comme tu as fait dans ton programme. Je sais que beaucoup de windowsien font ça pour pouvoir double cliquer sur leur programme et pour pouvoir lire le résultat, mais en vrai... ils devraient simplement ouvrir leur commandes ms-dos au bon endroit, puis y exécuter leur programme. C'est une considération "extérieure" au programme en tout cas.
- Note que si tu travailles avec un IDE (e.g. code::blocks, devcpp, visual studio sous windows et anjuta ou [ https://doc.ubuntu-fr.org/kdevelop kdevelop] sous linux) ce genre de question ne se posera pas. C'est intéressant de travailler avec un IDE (coloration syntaxique, console et débogueur intégré, etc...). Après, un éditeur évolué (notepad++ sous windows,
gedit
oukate
sous linux) est souvent amplement suffisant pour débuter.
Bonne chance