IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Force brute teste de strings


Sujet :

C++

  1. #1
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut Force brute teste de strings
    Bonjour,

    Je suis actuellement sur un projet qui consiste a forcer un md5. Cela étant je ne connais pas le nombre de caractère. Je dois donc retrouvé la chaine initial qui a permis de créer le md5. Je teste donc toutes les chaines de caractères de 1 a N. Cependant mon code n'est vraiment pas optimisé puisque je fais N boucle for qui me permettent donc de tester pour toutes les chaines de caractères de N boucle de longueur. Mais le projet spécifie que nous devons pouvoir choisir la longueur max que l'on va chercher.
    Je vous demande donc comment je peux faire pour changé mon code et avoir une longueur variable. Voici un bout de code qui vous permettra de mieux comprendre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    for(unsigned int j=0;j<tabLettre.size();j++)
    			{
     
    				Mot2=Mot1+tabLettre[j];
    				if (h1(Mot2)==h1(CODE))
    				{
    					cout<<"hashage: "<<h1(Mot2)<<endl;
    					return(0);
    				}
    				for(unsigned int k=0;k<tabLettre.size();k++)
    				{
    					Mot3=Mot2+tabLettre[k];
     
    					if (h1(Mot3)==h1(CODE))
    					{
    						cout<<"hashage: "<<h1(Mot3)<<endl;
    						return(0);
    					}
     
    					for(unsigned int l=0;l<tabLettre.size();l++)
    					{
    						Mot4=Mot3+tabLettre[l];
    						if (h1(Mot4)==h1(CODE))
    						{
    							cout<<"hashage: "<<h1(Mot4)<<endl;
    							return(0);
     
    						}
    						for(unsigned int m=0;m<tabLettre.size();m++)
    						{
    							Mot5=Mot4+tabLettre[m];
    							if (h1(Mot5)==h1(CODE))
    							{
    								cout<<"hashage: "<<h1(Mot5)<<endl;
    								return(0);
    							}
    Merci d'avance.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par cimestro Voir le message
    Bonjour,

    Je suis actuellement sur un projet qui consiste a forcer un md5.
    Attention!!! Ce projet pourrait te placer très en porte à faux avec les lois sur le piratage informatique
    Cela étant je ne connais pas le nombre de caractère.
    Tu n'en a -- a priori -- pas besoin, parce que MD5 agit comme une "somme de contrôle" : la même chaine de caractères fournira toujours la même somme, et deux chaines de caractères dans lesquelles un seul caractère est différents fourniront des sommes suffisamment différentes pour que l'on ne puisse pas douter du fait qu'elles sont différentes.

    Par contre, "en cherchant bien", on peut "assez facilement" trouver plusieurs chaines (chacune étant composées d'un nombre de caractères potentiellement différents) qui produiront la même somme (c'est ce que l'on appelle les "collisions"). Si tu trouvent deux chaines de caractères produisant la même somme de contrôle, elles seront considérées comme identiques, et ce, même si l'une des chaines de caractères n'est composée que de 10 caractères alors que l'autre en contient 1000.

    Je dois donc retrouvé la chaine initial qui a permis de créer le md5.
    C'est malheureusement impossible, car, MD5 est un algorithme que l'on pourrait qualifier de "destructif": il n'y a aucun moyen de retrouver le contenu qui a permis de générer la somme de contrôle.

    Cependant mon code n'est vraiment pas optimisé
    Ce qui est normal pour de la "force brute"... à défaut de connaitre la chaine de caractères d'origines

    Mais le projet spécifie que nous devons pouvoir choisir la longueur max que l'on va chercher.
    Ben, précises la, et arrête toi quand tu atteint la taille indiquée

    Ceci dit, plus tu acceptera que la chaine de caractères soit longue, plus tu auras de chance de tomber sur une chaine créant une collision : avec une chaine de maximum 10 caractères, les chances restent particulièrement minces (à moins, bien sur, que la chaine d'origine n'ait contenu elle-même moins de dix caractères )
    Je vous demande donc comment je peux faire pour changé mon code et avoir une longueur variable.
    Ben, a priori, tu devrais commencer par une boucle qui s'occupe de traiter les mots de 1 à maxLettres (cette deuxième valeur étant introduite par l'utilisateur, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(size_t tailleMot = 1; tailleMot < maxLettre; ++i){
        /* ici dedans, il faut tester toutes les permutations possibles pour les mots de tailleMot lettres */
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut
    La taille de la chaîne initial me permettra de pouvoir tester la rapidité entre mon programme et un autre programme. la est l’intérêt de mon projet. Une programme séquentiel contre un programme avec des threads.

    les taille de ma chaîne ne sera pas grande ( -10 caractères) lorsque je trouverais une chaîne qui correspond a mon md5 se sera forcement la chaîne initial non?

    Je comprends bien ce que tu veux faire dans la boucle mais je ne vois pas comment faire. C'est d'ailleurs a ce niveau la que je bloque. Je n'arrive pas a reproduire ce que j'ai fais avec des boucle for imbriqué en une seul boucle for.

    Merci

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par cimestro Voir le message
    La taille de la chaîne initial me permettra de pouvoir tester la rapidité entre mon programme et un autre programme. la est l’intérêt de mon projet.
    Oh, à ce moment là, on entre en phase de démonstration, et les dés sont "pipés" : tu introduit une chaine de caractères quelconque, mais tu sais exactement ce que tu as introduit

    Partant de là, tu connais forcément la taille de la chaine de caractères d'origine, et tu peux donc travailler sur des chaines de caractères de la taille en question

    les taille de ma chaîne ne sera pas grande ( -10 caractères) lorsque je trouverais une chaîne qui correspond a mon md5 se sera forcement la chaîne initial non?
    En toute honnêteté, je ne pourrais même pas forcément te le garantir, ayant quelque peu oublié le mode de fonctionnement de l'algorithme md5.

    Mais, il faut te dire que, même si tu limites tes chaines de caractères aux 26 lettres (majuscules et minuscules mélangées) de l'alphabet, chaque caractère de la chaine de caractères peut prendre 52 valeurs différentes, et que, pour une taille donnée, tu te trouve donc confronté à 52nombre de caractères chaines de caractères différentes.

    Valeur à partir de laquelle il faut encore compter avec le paradoxe des anniversaires
    Je comprends bien ce que tu veux faire dans la boucle mais je ne vois pas comment faire. C'est d'ailleurs a ce niveau la que je bloque. Je n'arrive pas a reproduire ce que j'ai fais avec des boucle for imbriqué en une seul boucle for.
    Ben, en fait, c'est "relativement simple" : tu utilises cette boucle pour créer une chaine de caractères avec tous des 'a', ce qui te donne:
    • au premier passage, la chaine "a"
    • au deuxième passage, la chaine "aa"
    • ...
    • au dixième passage, la chaine "aaaaaaaaaa"


    A partir de là, tu utilise ta chaine de caractères un peu comme un compteur kilométrique de voiture : tu fais systématiquement varier le dernier caractère de la chaine, le faisant passer à b, puis à c, ... puis à zQuand le dernier caractère vaut z tu le fait passer à A, et tu continue à le faire passer par les autres lettres de l'alphabet (en majuscules, cette fois)
    Lorsqu'il atteint la dernière valeur possible (Z si tu as bien suivi), tu travaille exactement de la même manière que lorsque tu passe de 9 à 10 : je passe à 0, je retiens 1, sauf que, en l'occurrence, tu repasse à a et que tu ajoute 1 à l'avant dernier, qui suivra exactement le même raisonnement avec l'anté-penultième caractère, qui suivra le même raisonnement avec celui qui le précède, et ce, jusqu'à ce que ta chaine de caractères ne soit composée que de Z .

    Si tu obtiens la même somme de contrôle à un moment donné, c'est que tu as gagné : tu as au minimum trouvé une collision possible qui fera l'affaire. Si tu en arrives à un point où la chaine de caractères n'est composée que de Z sans avoir retrouvé la bonne somme de contrôle, tu a perdu

    Je vais te laisser réfléchir à la logique à mettre en oeuvre pour utiliser ta chaine de caractères comme un compteur, mais le raisonnement est là
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut
    Merci de ta réponse encore une fois .

    J'ai finalement fais une séance intensive sur mon code. Je suis parti sur ce que tu m'a dis et j'ai finalement réussi. J'ai donc fais une boucle for qui correspond a la taille de ma chaine. Dans celle-ci j'y est mis un while qui parcours tous mes char de teste et qui grâce a de nombreux compteur ( for(int i=0; i<TailleMot; i++)) qui me permette de faire une sorte de compteur kilométrique comme tu m'a dis.

    Merci beaucoup. Plus qu'a threader tous ça et le tour et joué.

    Sujet résolu

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Si tu me montre ton code, je te montre le mien, car je me suis amusé, juste après mon intervention précédente, à voir comment je mettrais cette logique en place (sans toutefois calculer la somme md5 des différentes chaines de caractères)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut
    Je te l'ai envoyé en message privé parce que j'ai pas trop envie que tous les étudiants de ma promo voit mon code. Plusieurs personne savent que j'avais posté sur le forum donc si je pouvais évité que tous mon code tourne .

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Et, quand bien même, tous les étudiants de ta promo verraient ton code, où serait le problème Crois tu vraiment avoir des connaissances en cryptoanalyse telles que ton code, à ton deuxième essais, mérite le nobel d'informatique
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut
    Bon je mets ça la en espérant que ça pourras aider des gens . Voila la methode que j'ai fais. J'ai essayé de commenter le plus possible. Si vous voyez des choses a améliorer sans changer tous l'algo je suis preneur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    using namespace std;
    #include <string.h>
    #include <cmath>
    #include <thread>
    #include <pthread.h>
    #include <atomic>
    #include <iostream>
    #include <stdio.h>
    #include <time.h>
    #include <vector>
     
    int main()
    { 
    	string CODE; // A MODIF AVEC UN HASH MD5 DE LA LIB CRYPTO
    	cout<<"Entrez votre code"<<endl;
    	cin>>CODE;
    	float temps;
        clock_t t1, t2;
        t1 = clock();
    	vector<char> tabLettre(0);
    	char LettreMaj='A';
    	char LettreMin='a';
    	for (int i=0;i<26;i++)
    	{
    		tabLettre.push_back(LettreMaj);
    		tabLettre.push_back(LettreMin);		
    		LettreMin++;
    		LettreMaj++;
    	}		
    	int TailleMAX=5;//Mis sur 5 parce que c'est long :)
    	vector<char> modif(0);//Creation d'un vecteur qui va stocker des char qui permets donc de pouvoir suivre l'avancement dans le while
    	vector<int> compteur(0);//Creation d'un compteur qui va permettre le bon fonctionnement de mon while ( changement de char arrivé a z)
    	for(int tailleMot = 1; tailleMot <= TailleMAX; tailleMot++)
    	{
    		modif.push_back('A');//On rajoute une case au vecteur
    		compteur.push_back(0);//On rajoute un compteur
    		for(int i=0;i<tailleMot;i++)//On va initialiser au debut
    		{
    			compteur[i]=0;
    			modif[i]='A';
    		}
    		while(1)
    		{
    			bool iteration=false;// variable bool permettant de ne pas changer tous le temps si seulement un z est present. Dans le mot par exemple azaa. sans cette variable la prochaine chaine serais baaa alors que l'on veut azab
    			if(compteur[0]==52)//Si nous avons compteur[0]==52 alors cela veut dire que nous somme sur la chaine zzz ( nbr de char = tailleMot )
    			{
    				break;
    			}
    			string s=""; //Initialisation de s
    			for (unsigned int i = 0; i < modif.size(); i++) //boucle pour transformer mon array en string
    			{
    				s = s + modif[i];
    			}
    			if (s==CODE)//condition de verification
    			{
    				cout<<"Trouvé :)"<<endl; 
    				t2 = clock();
    				temps = (float)(t2-t1)/CLOCKS_PER_SEC;
    				printf("temps = %f\n", temps);
    				return(0);
    			}
    			if(compteur[tailleMot-1]<52)//condition si nous avons une lettre différente de z sur le dernier char
    			{
    				compteur[tailleMot-1]=compteur[tailleMot-1]+1;//on autoincremente le compteur
    				modif[tailleMot-1]=tabLettre[compteur[tailleMot-1]];//modif va aller chercher la valeurs de la compteur case de mon vector contenant les char de test
    			}
    			for(int z=(tailleMot-1);z>0;z=z-1)//boucle for qui va verifier si le compteur == 52. Si c'est le cas alors on va modifier la lettre de modif puis et on va verifier pour celui d'apres. Si nous avons une fois compteur different de 52 alors on mets iteration a true pour eviter le cas de azaz ou le deuxieme z serais remis a 'A'
    			{
    				if(compteur[z]>=52 && iteration==false)
    				{		
    					modif[z-1]=tabLettre[compteur[z-1]+1];//on remets a 0 les valeurs pour modif et pour les compteur
    					compteur[z-1]=compteur[z-1]+1;
    					modif[z]='A';
    					compteur[z]=0;
    				}
    				else
    				{
    					iteration=true;
    				}
    			}
    		}
    	}
    	exit(0);
    }

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Ton code est franchement pas mal, pour un débutant, mais il laisse quand même beaucoup de place à l'amélioration:

    1- On n'utilise JAMAIS la directive using namespace std; : cette possibilité a été rajoutée lorsque le commité de normalisation du langage a décidé permettre l'utilisation des espaces de noms et, par voie de conséquence, de placer les fonctionnalités issues de la bibliothèque standard dans l'espace de noms std.

    A l'époque, la base de code existante en C++ était déjà importante, et il s'agissait de donner un moyen au développeurs de garder un code (écrit avant la normalisation) capable de compiler en ne nécessitant "qu'un minimum" de modifications.

    la directive using namespace n'a donc été proposée que pour éviter aux développeurs d'avoir à parcourir leurs dizaines / centaines / milliers de fichiers à la recherche de tous les endroits du code où il faudrait rajouter le fameux std::.

    On ne peut décemment pas dire que le code que tu écrit aujourd'hui soit "assez vieux" pour mériter d'utiliser ce "hack", car cela fait maintenant plus de vingt ans que les fonctionnalités de la bibliothèque standard sont placées dans l'espace de nom std

    2- Les fichiers "standards" qui portent l'extension .h (comme time.h stdio.h ou string.h) sont des fichiers d'en-tête issus du C, et devraient être évités. Si tu en as vraiment besoin (généralement pour te permettre de dialoguer avec une bibliothèque développée en C), tu devrait utiliser les fichiers spécifiquement issu du C++, qui ne présentent pas d'extension, et dont le nom est préfixé par la lettre c (ex : ctime, cstdio ou encore cstring).

    Mais, a priori, tu n'en auras pas besoin, ne serait-ce que parce que l'on préférera utiliser les fonctionnalités similaires-- plus sécurisantes à l'emploi dans de nombreux cas -- issues directement du C++

    Le fichier pthread.h est sensiblement dans la même veine : il fournit les fonctionnalités de threads posix exposées par une bibliothèque nommée pthreads (que l'on retrouve sous windows), et fait au final double emploi avec les fonctionnalités issues du fichier <thread>

    3- Pour en finir avec le chapitre des fichiers d'en-tête: tu dois veiller à n'inclure à tout moment que les fichiers dont tu as vraiment besoin:

    Tu n'as aucun besoin des fichiers d'en-tête dont l'origine vient du C (string.h, cmath, pthread.h, stdio.h ) dans ton code actuel. Tu n'as donc aucune raison de les ajouter.

    De plus, si tu veux travailler avec des chronos corrects, tu devrais utiliser les fonctionnalités exposées par le fichier d'en-tête chrono, au lieu d'utiliser les fonctionnalités issues du C.

    Enfin, comme tu n'utilises pas les threads pour l'instant -- même si tu prévois d'y avoir recours par la suite -- tu n'as aucun besoin d'inclure le fichier d'en-tête thread

    4- Ton code est suffisamment clair pour que tu aies pu t'éviter la peine d'y rajouter des commentaires. Il faut savoir que, à part lorsqu'ils poursuivent un but didactique, les commentaires qui paraphrasent le code (comprend : qui tentent d'expliquer ce que fait chaque ligne du code, ou presque ) sont plutôt nocifs qu'autre chose:

    Un code doit pouvoir se lire comme un bon roman, sans avoir besoin d'explications supplémentaires. Et, pour ce faire, il n'y a pas de miracle, il faut
    1. choisir correctement les noms de te (types de ) données et de tes fonctions
    2. respecter le SRP (Single Responsability Principle ou principe de la responsabilité unique)
    3. respecter la règle "une ligne == une instruction (ou déclaration d'une seule variable)
    4. veiller à déclarer tes données au plus près de leur utilisation

    Hormis le SRP, tu avais presque réussi à respecter les trois autres règles. Il n'y a que pour t1 et t2 que tu te sois un peu fourvoyé:

    t1 aurait sans doute gagné à être appelé timeBegin ou n'importe quel autre nom de ton cru qui permette d'indiquer clairement qu'il s'agit du repère de temps utilisé pour représenter le début de ton chronomètre. Quant à t2, vu que tu ne l'utilises pour la première fois qu'au niveau de la ligne 58 de ton code, elle aurait pu s'appeler timeEnd (ou tout autre nom de ton cru) et être déclarée ... juste avant son utilisation.

    5- Enfin, le SRP est sans doute, parmi les cinq principe SOLID, celui qu'il faut impérativement veiller à respecter en toute circonstances. Il est dommage que tu ne l'aies pas respecté

    Enfin, comme promis, voici le code que j'ai personnellement mis au point, avec les explications qui vont bien

    J'ai commencé par me dire que, chaque fois que je changeais un caractère dans ma chaîne de caractères, j'avais besoin de deux informations "conjointes" : le caractère "suivant", celui par lequel je devais remplacer le caractère "courant", et une information pour savoir si je devais effectuer le report sur "le caractère d'à coté".

    J'aurais pu utiliser une std::pair<char, bool>, mais j'ai préféré créer une notion bien spécifique sous la forme de la structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Result{
        char nextChar;
        bool overlaps{false};
    }
    Grâce à cette structure, je me suis dit que je pouvais désormais créer une fonction qui me fournisse toutes les informations dont j'ai besoin pour me permettre de changer un caractère particulier de ma chaine de caractères et qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Result nextCharacter(char current){
        static const std::string maybe{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
        auto found = maybe.find(current) +1;
        Result temp;
        if(found == possible.size()){
            found = 0;
            temp.overlaps = true;
        }
        temp.nextChar = found;
        return temp;
    }
    Tu remarqueras que si je voulais rajouter les chiffres ou les caractères spéciaux (tels que @,#,! et autres signes de ponctuation), je pourrais le faire très facilement et dans n'importe quel ordre, pour autant que je me limite aux caractères imprimables (ceux qui arrivent après l'espace dans la table ASCII, celui-ci étant compris dans le lot)

    Si je voulais pouvoir travailler avec n'importe quel caractère ASCII, dont, entre autres, les caractères non imprimables (ceux qui présente un indice dans la table ASCII compris dans l'intervalle [0,32[ ), par exemple, pour traiter des fichiers binaires, je devrais sans doute faire autrement, mais bon...

    Avec cette fonction, j'avais tout ce qu'il fallait pour créer une deuxième fonction capable de modifier la chaine de caractères pour lui donner un air de compteur. Je lui ai donné la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void rotate(std::string & str){
        auto position = str.size() -1;
        bool again{false};
        do{
            auto result = nextCharacter(str[position]);
             again = result.overlaps;
             str[position]=result.nextChar;
             if(again){
                 --position;
             }
        } while(position >=0 && again)
    }
    Et je me suis rendu compte que j'étais peut-être bien un peu trop directif en te disant qu'il fallait faire tourner en priorité le caractère de droite, qui correspond au unités sur les nombres.

    Car, soyons honnête : pour nous que l'on passe par les chaines "aaa", "aab" ... "aaZ" ... "ZZZ" ou que l'on passe par les chaines "aaa","baa" ... "Zaa" ... "ZZZ", cela ne change absolument rien pour nous j'ai donc renommé cette fonction en rotateRight, pour indiquer qu'elle parcoure la chaine de caractères "de droite à gauche", et j'ai créé sa soeur jumelle capable de parcourir la chaine de caractères ... de gauche à droite, en lui donnant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void rotateLeft(std::string & str){
        size_t position{0};
        bool again{false};
        do{
             auto result = nextCharacter(str[position]);
             again = result.overlaps;
             str[position]=result.nextChar;
             if(again){
                 ++position;
             }
        }while(position < str.size() && again);
    }
    Avec un avantage certain lorsque l'on voudra travailler sur plusieurs thread : chaque fonction pourra travailler à "un bout de la chaîne", et elles pourront se rejoindre au milieu (si aucune des deux n'a trouvé la solution recherchée, du moins)

    Il ne me manquait plus que le moyen de générer la chaine de caractères "de départ" sur base du nombre de caractères souhaités. Non, en fait, je devais pouvoir générer deux chaînes de caractères à chaque fois : une représentant la chaîne de départ, et l'autre représenant la condition de fin de la boucle. Et, pour représenter ces deux chaines de caractères, j'ai de nouveau créé une structure à laquelle j'ai donné la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Strings{
        std::string begin;
        std::string end;
    };
    à laquelle j'ai adjoint une fonction capable de générer les deux chaines selon mes spécifications, et à laquelle j'ai donné la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Strings generateStrings(size_t size){
         Strings temp;
         temp.begin.append(size, 'a');
         temp.end.append(size,'Z');
        return temp;
    }
    Enfin aller vraiment jusqu'au bout des choses, vu que la seule responsabilité de la fonction main() devrait être de servir de "point d'entrée" au programme, j'ai créé une fonction qui s'assure de parcourir l'ensemble des chaines de caractères composées d'un nombre bien précis de caractères sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void computeStrings(size_t size){
        auto strings = generateStrings(size);
        size_t count{0};
        while(strings.begin != strings.end){
            rotateRight(strings.begin);
            std::cout<<strings.begin<<"\n";
           ++count;
        }
        std::cout<<"computed "<<count<<" strings of size "<<size<<"\n";
    }
    Cette fonction va afficher et compter toutes les chaines de caractères qu'il est possible de générer.

    Bien sur, tu peux en adapter le code pour ne pas afficher les chaines, ou pour ne pas afficher le décompte final, ou pour faire "autre chose" (comme calculer la somme md5) avec chacune des chaines de caractères obtenues, vu que mon code reste malgré tout du domaine de la POC

    Si tu envisages de travailler avec plusieurs threads, c'est -- a priori -- au niveau de cette fonction qu'il faudra travailler

    Je pouvais désormais créer ma fonction principale en lui donnant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(){
        for(size_t i = 1;i<=5;++i)
            computeStrings(i);
        return 0;
    }
    de manière traiter toutes les chaines de caractères dont le nombre de caractères est compris entre 1 et 5 inclus. Bien, on pourrait adapter le code pour demander à l'utilisateur une limite haute et une limite basse concernant le nombre de caractères des différentes chaînes, voir pour demander l'introduction d'une chaine de caractères "témoin", et tout ce que tu peux envisager d'autres

    Fier du travail accomplis (cela m'avait demandé royalement 20 minutes ), je me suis rendu compte que la fonction nextCharacter, pour rapide qu'elle soit, risquait peut-être de présenter un problème de performance à cause de la recherche du caractères dans la chaine appelée maybe car il s'agit malgré tout, dans le pire des cas, de parcourir les 52 caractères de cette chaine pour trouver le caractères 'Z', et que l'on pourrait donc rendre cette logique potentiellement plus efficace (il faudrait, pour bien faire, un benshmark pour s'en assurer )

    Je me suis en outre rappelé que les lettres majuscules arrivaient avant les lettres minuscules dans la table ASCII, et qu'il y avait -- en outre -- "un certain nombre" de caractères "particuliers" entre le 'Z' et le 'a'.

    J'ai donc modifié ma fonction nextCharacter pour lui donner la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Result nextCharacter(char current){
        ++current;
        Result temp;
        if(current >'z'){
            temp.overlaps = true;
            current = 'A';
        }else if(current >'Z' && current <'a'){
            current = 'a';
        }
        temp.nextChar = current;
        return temp;
    }
    Soyons bien clair : je n'ai absolument aucune preuve d'une meilleure efficacité de cette fonction-ci. Je n'ai -- au mieux -- que l'intuition qu'elle pourrait s'avérer plus efficace

    En outre, cette version m'oblige à adapter la logique de la fonction generateStrings, pour lui donner la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Strings generateStrings(size_t size){
         Strings temp;
         temp.begin.append(size, 'A');
         temp.end.append(size,'z');
        return temp;
    }
    vu que les majuscules arrivent désormais avant les minuscules (ce qui ne nous pose malgré tout, a priori, aucun problème ).
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre actif
    Homme Profil pro
    iut informatique
    Inscrit en
    Novembre 2018
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : iut informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 34
    Par défaut
    Merci beaucoup. JE prendrais le temps de regarder ça dans la journée. J'ai fini les threads sur mon algo qui on été assez simple a mettre en place par rapport a ce que je pensais . Je vais changer tous les points que tu me dis.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 25/06/2008, 12h12
  2. Test Egalite string (super basique)
    Par ced600 dans le forum VBScript
    Réponses: 1
    Dernier message: 07/12/2007, 15h59
  3. Réponses: 2
    Dernier message: 14/06/2007, 11h59
  4. tests sur String
    Par frouge dans le forum Collection et Stream
    Réponses: 1
    Dernier message: 07/06/2006, 11h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo