C'est dommage.
Il serait plus constructif de voir comment faire "correctement" à une fonctionnalité plutôt que d'essayer de comprendre un code très très mal écrit qui fait 10 choses en même temps.
Explique-moi ?
Expliquer un code horriblement complexe pour faire pas grand-chose ??? (et il manque un bout)
Pour moi, cette horreur ne fait que (et très très mal) :
- lire le contenu d'un fichier
- interprète le contenu de ce fichier sous forme d'une chaîne de caractère contenant 3 nombres pour le numéro d'année , du numéro de mois et de numéro du jour séparé par une farandole de séparateur
- "vérifie" que la date obtenue est valide pour une date du calendrier grégorien (enfin je l'interprète comme ça).
- modifie l'une des 2 variables date_de_reprise ou date_de_sortie, mais jamais les 2. J'espère que c'est des champs de la classe (donc faudrait un préfixe "m_") et pas de variables globales ou statiques à la con.
Déjà, c'est 4 trucs, donc 3 de trop.
Et, comme d'habitude, le nom de la fonction n'a rien à voir avec ce qu'elle fait réellement (même si c'était la cas, purée que le nom serait compliquée => fait trop de chose).
EDIT: après avoir jeté un coup d’œil au GitHub, cette fonction horrifique ("afficher_Date_de_reprise_ou_de_sortie") n'y est pas mais "afficher_Date_de_reprise" y est et elle est du même acabit.
Si on calque la fin de cette dernière ("afficher_Date_de_reprise"), la fonction "afficher_Date_de_reprise_ou_de_sortie" a un nom un peu plus logique, car elle ferait bien un affichage à la fin.
C'est donc un 5ème trucs qu'elle ferait, donc les 4 autres serait de trop.
Vous voulez vraiment qu'on disserte sur des dizaines de lignes sur un machin qu'on ne devrait jamais écrire ???
Si on fait les choses biens, on découpe le travail en tache simple.
Déjà "lire le contenu d'un fichier", ça a dû être fait ailleurs de manière bien plus propre.
Donc les paramètres "d_filename" et "nomFichier", qui portent quasiment le même nom, preuve que c'est pas très malin, on les dégage.
La seule chose qui nous intéresse en entrée, c'est le contenu du fichier, donc on passe en paramètre seulement une "const std::wstring" directement avec le contenu du fichier (qui a été bien "mieux" récupéré avant dans le processus).
Déterminer les 3 valeurs constituants une date dans une chaîne de caractère, une simple "expression régulière" fera le travail de manière bien plus claire concise que l'horreur du code de "Cinema::afficher_Date_de_reprise_ou_de_sortie"
Déterminer qu'un triplet de nombre est une date valide dans le calendrier grégorien, si c'est pas dans le standard, ça doit exister sur le net : Google est mon ami:
Question posée :
how to verify date in C++
Premier résultat :
http://www.zedwood.com/article/cpp-c...20user%20input.
La fonction checkdate qui y est présenté me semble très correcte :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
bool checkdate(int m, int d, int y)
{
//gregorian dates started in 1582
if (! (1582<= y ) )//comment these 2 lines out if it bothers you
return false;
if (! (1<= m && m<=12) )
return false;
if (! (1<= d && d<=31) )
return false;
if ( (d==31) && (m==2 || m==4 || m==6 || m==9 || m==11) )
return false;
if ( (d==30) && (m==2) )
return false;
if ( (m==2) && (d==29) && (y%4!=0) )
return false;
if ( (m==2) && (d==29) && (y%400==0) )
return true;
if ( (m==2) && (d==29) && (y%100==0) )
return false;
if ( (m==2) && (d==29) && (y%4==0) )
return true;
return true;
}
S'il y a des problèmes avec, on n'aura à corriger qu'à un seul endroit.
La modification de "une des 2 variables..." c'est tellement pourri qu'on pourra faire mieux.
EDIT: pour l'affichage, le 5ème trucs qu'on devine avec le code complet de "afficher_Date_de_reprise" dans GitHub , et qui serait raccord avec le nom de la fonction, faut pas mélanger l'acquisition/vérification des données (les 3 premières tâches de cette fonction trop longue) et l'affichage.
L'affichage en lui-même est tellement bateau qu'une fonction dédiée serait peut-être overkill.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
void Cinema::afficherDateRepriseOuSortie(){
afficherDate(m_dateReprise!=nullptr ? m_dateReprise : m_dateSortie);
}
void Cinema::afficherDate(const& myDate date){
... //mise en forme d'une date selon les règles d'affichage ad hoc
PrintTmp(...);
...
}
Je vais donner une implémentation simple d'une fonction qui se charge du décodage d'une chaîne de caractère contenant une date, plus simplement, plus facile à maintenir, plus souple, etc... que cette horreur de "Cinema::afficher_Date_de_reprise_ou_de_sortie":
Code : Sélectionner tout - Visualiser dans une fenêtre à part
#include <regex>
#include <iostream>
....
std::tm Cinema:
![:P](https://www.developpez.net/forums/images/smilies/icon_razz.gif)
arseDate(std::wstring& str)
{
//le seul truc non trivial est l'utilisation d'une expression régulière, Google est notre ami.
std::wregex date_regex(L"(\\d{4})(?:/|\\-|\\.|\\s)(\\d{2})(?:/|\\-|\\.|\\s)(\\d{2})");
std::wsmatch matches;
if (std::regex_search(str, matches, date_regex))
{
int year = std::stoi(matches[1].str());
int month = std::stoi(matches[2].str());
int day = std::stoi(matches[3].str());
if(checkdate(month,day,year)
{
std::tm date;
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
return date;
}
else
{
throw std::invalid_argument("Cinema:
![:P](https://www.developpez.net/forums/images/smilies/icon_razz.gif)
arseDate : La date passée en argument n'est pas valide.")
}
}
else
{
throw std::invalid_argument("Cinema:
![:P](https://www.developpez.net/forums/images/smilies/icon_razz.gif)
arseDate : Le format de l'argument n'est pas valide.")
}
}
...
Je vais donc essayer de ne pas m'attarder sur tous les problèmes dans la fonction "Cinema::afficher_Date_de_reprise_ou_de_sortie" qui à comparer avec la fonction "Cinema:: ParseDate" est un capharnaüm labyrinthique.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
const void Cinema::afficher_Date_de_reprise_ou_de_sortie(std::wstring& d_filename, const std::wstring& nomFichier)
C'est quoi ce "const", le compilateur devrait vous dire que c'est nimpornawak.
On passe sur le nom de la fonction qui n'a rien à voir avec ce qu'elle sensée faire.
2 paramètres quasi-identique, qui ne servent à rien à cause de l'assert à la ligne 3 : "assert((d_filename == createdBy_filename) && L"Erreur !!! Date de reprise... !");"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
assert((d_filename == createdBy_filename) && L"Erreur !!! Date de reprise... !");
Ca vérifie que le paramètre "d_filename" a bien pour valeur la même valeur que la variable globale/champ statique de la classe/autre connerie de variable à la con "createdBy_filename" sinon lance une exception avec le message "Erreur !!! Date de reprise... !".
Donc les paramètres "d_filename " et "nomFichier" ne servent à rien car la fonction n'est pas paramétrable (au sens mathématique de la chose).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
std::wstring d = lire_fichierTxt(nomFichier);
On remplit "d" avec le contenu du fichier dont le nom est la valeur du paramètre "nomFichier".
"d" comme nom de variable, il y a de l'abus!
C'est un truc qui n'a rien de spécifique à la fonction, autant le faire à l'extérieur de la fonction, avec des fonctions bien plus généralistes.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
std::size_t pos = 0;
Encore une variable avec un nom à la con, qui va servir à 100 choses différentes.
Dégagez ce type de variable et déclarez une variable par usage.
Et la valeur par défaut raisonnable d'un std::size_t pour une position dans un chaîne, c'est "std:: string:: npos", pas 0 (et "std:: string:: npos", c'est bien souvent -1 mais jamais 0).
Donc le code suivant,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
std::size_t pos = 0;
// year
int year = 0;
year = std::stoi(d, &pos);
devrait être, pour être un minimum maintenable:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
std::size_t year_len;
int year = std::stoi(d, &year_len);
et encore, comme vous vous foutez de la longueur de vos suites de chiffres, un code aussi simple que :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
int year = std::stoi(d);
fait aussi bien et tout aussi "robuste" (c'est un sarcasme).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
try
{
if (year <= 1900 || year >= 3001)
{
throw std::wstring(L"L'année illégale doit être l'année numérique - entre 1900 et 3001");
}
}
catch (runtime_error const& exception)
{
std::wcout << L"Erreur : " << exception.what() << std::endl;
}
Tout ce code juste pour envoyer sur la console un message d'erreur si year est compris entre 1900 et 3001 inclus.
Le calendrier grégorien est valide à partir de 1582, le cinéma a été inventé avant 1900.
Et c'est quoi qui arrive en 3001 ? Le nouvel Apocalypse selon Paco Rabane ?
cf. la fonction "checkdate " trouvée sur le net et postée ci-avant dans ce post.
Même si cette contrainte est foireuse, le code suivant fait strictement la même chose mais en plus direct :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
if (year <= 1900 || year >= 3001)
{
std::wcout << L"Erreur : L'année illégale doit être l'année numérique - entre 1900 et 3001" << std::endl;
}
Lancer une exception qu'on capture (via catch) systématiquement dans la même méthode n'a aucun putain d'intérêt.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
d = d.substr(4);
là, on va juste faire en sorte de supprimer de d les 4 premiers caractère.
Donc, pourquoi s'emmerder à passer la variable "pos" en ligne 9 ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
year = std::stoi(d, &pos);
Donc on supprime les 4 caractères représentant putativement l'année dans la chaîne de caractère "d" contenant le contenu du fichier.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
std::wcout << L"-/. ={" << d[0] << L"}" << std::endl;
Affiche dans la console le caractère en début de chaîne "d", donc le cinquième du fichier suite à l'exécution de la ligne 21 de votre code.
En l'encadrant devant par la chaîne "-/. ={", et derrière avec "}".
J'ai déjà indiqué plus d'une fois que faire des traces de débogage dans le console est une énorme CONNERIE.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
try
{
if (d[0] == L'-' || d[0] == L'/' || d[0] == L'.' || d[0] == L' ')
{
throw std::wstring(L"Illegal aaaaaaaa");
}
}
catch (runtime_error const& exception)
{
std::wcout << L"Erreur : " << exception.what() << std::endl;
}
d = d.substr(1);
Même conneries qu'aux lignes 10 à 21.
Là on vérifie juste que le 5ème caractère dans le fichier est soit "-" soit "/" soit "." soit un espace, sinon, on envoie encode des cochonneries dans la console.
Les lignes 36 à 79, c'est 2 fois les mêmes bêtises que les lignes 5 à 35 mais en cherchant le numéro de mois et le numéro de jours et en y faisant des vérifications complètement bancales.
cf. le code de la fonction "checkdate" qui fait tout cela de manière bien plus simple et correcte.
Les lignes 80 à 83, on initialise la variable "date", de type std::tm ( cf.
https://en.cppreference.com/w/cpp/chrono/c/tm) avec les informations glanées dans les lignes précédentes.
Les lignes 84 à 88, en fonction de la valeur de la variable "d_filename", soit on initialise la variable "date_de_reprise", soit la variable "date_de_sortie". (C'est complètement bancal comme approche.)
Partager