[Objective-C] Substitution Caesar et Vigenère
NSProbleme
Membre
Bonjour,
J'ai deux méthode Caesar et Vigenère qui me permettent de crypter ou decrypter un message en utilisant une clès.
Pour la méthode Caesar ca fonctionnement parfaitement, mais pour vigenère je ne comprends pas ce qui se passe car quand je fais un NSLog le résultat ne s'affiche pas forcement.
(Petit rappel
Caesar : j'entre un message et un chiffre puis j'obtiens un nouveau message avec les lettres décalés en fonction du chiffre.
Pour vigenère c'est pareil mais là la clef est un mot de même longueur que le message et j'obtiens un nouveau avec les lettres décalés en fonction de la valeur des lettres qui compose la clef)
(Boolean action : c'est quand j'appuie sur le bouton crypter renvoie true et inversement)
+(NSString*)Cesar:(NSString*)msg :(NSString*)cles :(Boolean)action
{
int intCles = [cles intValue];
if (!action){intCles = intCles*-1;}
NSString* sortie = @"";
int v = 0;
NSLog(@%@ IIII %i",msg,intCles);
for(int i ; i < msg.length ; i++)
{
int c = [msg characterAtIndex:i];
NSLog(@%c --- %i,c,c);
if((c>=(int)'a') && (c<=(int)'z'))
{
v = (int)'a'+intCles;
if (v<(int)'a'){v = (((c-(int)'z')+intCles)%26)+(int)'z';}
else{v = (((c-(int)'a')+intCles)%26)+(int)'a';}
}
else if((c>=(int)'A') && (c<=(int)'Z'))
{
v = (int)'A'+intCles;
if (v<(int)'A'){v = (((c-(int)'Z')+intCles)%26)+(int)'Z';}
else{v = (((c-(int)'A')+intCles)%26)+(int)'A';}
}
else { v=(char)c;}
sortie = [NSString stringWithFormat:@%@%c",sortie,v] ;
}
NSLog(@< %@ >",sortie);
return sortie;
}
+(NSString*)Vigenere:(NSString*)msg :(NSString*)cles :(Boolean)action
{
NSString* sortie = @"";
NSString* intCles;
NSString* c ;
for(int i ; i < msg.length ; i++)
{
intCles = [NSString stringWithFormat:@%i,((int)[cles characterAtIndex:i] - (int)'a')+1];
c = [NSString stringWithFormat:@%c,[msg characterAtIndex:i]];
sortie = [NSString stringWithFormat:@%@%@",sortie,[Substitutions Cesar:c :intCles :action]];
}
return sortie;
}
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Je vois que tu es nouveau, merci d'aller te présenter dans la section "Présentation des Membres" pour que l'on sache plus sur ton parcours, ton niveau et ton expérience et que l'on adapte nos réponses en conséquence
Bonjour,
J'ai crée une master-detail application
DetailViewController.m
Qui t'a enseigné l'Objective-C ?
Est-ce que t'as appris des autres langues auparavant ?
Pourquoi choisir Objective-C au lieu de Swift ?
À part de ces questions...
Ton code est très mal formé. Il manque les espaces et les lignes d'espace.
Les noms des méthodes ne devraient ni commencer avec une majuscule, ni contenir les tirets bas
Les noms des propriétés, vars et méthodes sont vraiment cryptiques ; il vaut mieux les nommer plus descriptifs.
Tu traites un NSString comme une liste de int (32 bits) ; en fait, c'est une liste de unichar (unsigned short / 16 bits). En plus, en traitant un NSString, il faut considérer que l'on y pourrait trouver les "grapheme clusters" (symboles unicode qui se composent de plus de 1 unichar)
En convertant les chars littéraux ('A', etc) vers les ints, tu ignores qu'ils ne composent que de 8 bits et tu les mets dans un int de 32 bits.
Peut-être ça marche dans ce petit exemple mais, un jour, tu trouveras que ces trucs puissent te mordre >:D
Le construction if..else dans Cesar est douteux, voir ambigu, sur son chemins d'exécution.
J'ai fait de la ménage sur ton code pour te montrer quelques procédures meilleurs.
Maintenant le code est un peu plus clair mais il manque encore de travaille. Néanmoins, je crois que si tu examinais la méthode substituerEnVigenere:avecCles:action: , tu y trouveras une faute de logique.
Ton codage Caesar me parait compliqué, avec des if-else dans tout les sens.
Voici une fonction Caesar écrite en Swift (Je serais incapable de le coder en objective-C, même si ma vie en dépendait).
Exemple d'utilisation :
Affichage :
Tu peux remarquer que l'espace a aussi été transformé en un autre caractère, ce qui améliore l'efficacité du codage. Avec ton système, seules les lettres "a-z" et "A-Z" sont cryptés. Le mien code TOUT, y compris les signes de ponctuation, les minuscules accentués, les espaces et les emojis.
Malheureusement, unicodeScalars n'existe pas sur NSString ; du coup, c'est beaucoup plus difficile de décaler les "characters" d'un NSString en Objective-C >:(
Comment cela fonctionne ?
Pour des raisons de compatibilité avec Objective-C, Swift peut utiliser NSString pour stocker des chaines de caractères, mais il possède aussi son propre type, plus souple : String.
String possède des fonctions d'énumération, ce qui permet de lire les caractères d'une manière simple, sans passer par une boucle classique.
a
a
C'est plus propre et plus lisible que la boucle habituelle. Affichage :
a
a
On peut aussi énumérer le texte de manière à récupérer directement des caractères Unicode. C'est une approche plus moderne.
a
a
L'opérateur .value permet d'obtenir la valeur numérique d'un caractère Unicode. Affichage :
a
a
La représentation numérique d'un Unicode est un UInt32 (entier 32 bits non signé). C'est beaucoup plus long que les 8 bits de l'ASCII, mais cela permet de stocker les millions de caractères Unicodes possibles dans un seul chiffre (caractères français, russes, japonais, chinois, grecs, hindous, emojis, etc..).
Une simple addition donne le code Caesar.
a
a
La fonction UnicodeScalar permet de convertir un entier 32 bits non signé en caractère Unicode. Il y a une petite subtilité dans le code. Théoriquement, cela devrais s'écrire comme :
a
a
Ce n'est pas le cas à cause des mécanismes de sécurité intégré de Swift. Il est possible que la conversion d'un entier vers un Unicode échoue, à cause d'une valeur erronée. C'est le genre de bug qui peut planter un programme classique.
En Swift on écrit :
a
a
Cela veut dire "on essaye de réaliser l'opération nouveauCaractere = UnicodeScalar(caesar)". Si c'est bon, on exécute les instructions entre accolades, sinon on ne fait rien. On peut même afficher un avertissement pour signaler un problème.
a
a
J'utilise une String vide pour stocker le résultat du codage Caesar.
a
a
L'opérateur append() permet d'ajouter du contenu à une String. Mais il ne sait pas comment ajouter un Unicode à une String, alors j'ai besoin de convertir l'Unicode en une nouvelle chaà®ne de caractère.
a
a
Et voilà , c'est (presque) simple. J'espère t'avoir convaincu que Swift c'est le Bien pour un novice ..
a
OBJECTIVE-C C'EST LE MAL !!! >:D
Bah non ! Dans ce cas, ce n'est pas Objective-C qui est mal mais sûrement NSString ::) >:D
Grâce à ton exemple, j'ai réussi (d'une façon). Ce n'est pas avec les unicode scalars mais les unichar, qui me semble suffisant pour l'exemple donné.
Draken - tu te rends compte que nous avons fait les devoirs de vacances pour NSProbleme ? ::)
C'est pas grave, si cela le persuade de l'infini supériorité du Swift .. ::)
En y réfléchissant, il y a un problème potentiel dans ton code, Joanna. Tu fais le calcul sans vérifier si le résultat est un caractère Unicode valide. Il doit y avoir des "trous" dans la liste des UniCodes, surtout avec les caractères complexes composés de plusieurs informations.
Le cryptage d'un caractère étendu, comme un symbole chinois ou un émoji pourrais créer un caractère non valide, avec des résultats imprévisibles (erreur d'affichage, plantage, etc..). Dans le meilleur des cas, le "bad caractère" ne seras pas affiché, altérant le message.
Cela ne peut pas arriver dans mon exemple en Swift, UnicodeScalar() vérifiant la validité de la conversion.
g
a
Je n'y ai pas pensé en écrivant le code. C'est Swift qui m'a forcé à utiliser un "if let", preuve qu'il est plus malin que moi. Ou plutôt que les ingénieurs d'Apple ont bien fait leurs travail en concevant les bibliothèques d'objets Swift.
C'est clair !
Mais c'est toujours utile pour un débutant en programmation de savoir qu'un code simple, ayant l'air de fonctionner, puisse présenter des failles dans certaines situations.
Bonjour,
Pour revenir au début ^^, j'ai fait les modifications. Pour la méthode Cesar et j'ai un petit problème j'ai rien en sortie et j'ai voulu voir ce qui se passe avec un NSLog mais le NSLog qui dans la boucle for n'affiche rien.
En fait j'ai utilisé le modulo et le reste pour qu'on puisse entrer n'importe quelle valeur positif ou négatif pour la clef.
Si je veux crypter "a" avec la clef "-1" , j'obtiendrais "z",
pour crypter "a" avec la clef "27", j'obtiendrai "b".
1. T'as utiliser int au lieu de NSUInteger (msg.length est NSUInteger). ça devrait être :
2. Tu n'as pas initialiser i ; du coup, sa valeur est indéterminée
3. Tu continues à utiliser les noms brefs ; pour la maintenabilité du code, la lisibilité est beaucoup plus important que la brièveté
Tu dis que le code vigenère est une chaà®ne de même longueur que le message à coder, mais ce n'est pas ça. En fait c'est un code cyclique qui se répéte sans cesse. Exemple :
Code vigenère "abc"
Message à coder "Demain, je mange une pizza." - 27 caractères
Séquence de codage : "abcabcabcabcabcabcabcabcabc" - 27 caractères
Plutôt que de fabriquer une longue chaà®ne de codage, il est plus simple d'utiliser un objet calculant la valeur du décalage à un moment t, en gérant lui-même la répétition des cycles.
Exemple en Swift (oui je sais, ta drogue c'est l'Objective-C, mais les principes sont les mêmes) :
a
a
A sa création, la classe CodeCyclique() reçoit un texte dont les caractères sont convertis en entiers et stockés dans un tableau.
a
a
A chaque appel de la méthode decalageCyclique(), l'objet fournit la valeur de décalage courante, tout en gérant le cycle de rotation. Par exemple, pour obtenir les 8 premières valeurs de décalage, il faut appeler la méthode 8 fois :
Affichage :
Voici une version du code de Vigenère, quasi-identique à ma version Swift du code de Caesar. La seule différence est l'utilisation d'un
décalage cyclique au lieu d'une valeur constante.
Exemple de code :
a
Résultat des courses :
a
En reprenant la phrase du début, cela donne :
Le décodage, c'est exactement la même chose que le codage en inversant le sens du décalage cyclique.
a
a
Exemple :
a
a
Affichage :
Et c'est tout ..
Mais je crois que NSProbleme ne veut que jouer avec les lettres A-Z/a-z, ignorant les lettres accentuées ou tout autres caractères. Ce qui me dit que c'est surtout un exercice académique, pas pour apprendre comment bien coder.
NSProbleme, ai-je raison ?
En fait c'est juste pour voir les algorithmes de cryptage j'ai encore 5 ou 6 algo à coder (playfair, hill, DES, ect), on a le choix entre coder en objectif-c ou android, on peut aussi le faire en swift, j'aurais du le faire en swift ça n'a pas l'air plus compliqué que les autres langages mais comme on a pas de cours sur swift et que je connait plutôt bien android j'ai pris objective-c ^^.
Après pour prendre en compte tous les caractères, y a vraiment d'instruction la dessus, j'adapterai s'il faut ^^.
J'ai réussi à faire tourner les deux méthode César et Vigenère.
Merci de vos aides
C'est une occasion comme une autre d'entraà®ner mes "muscles pédagogiques". J'envisage de rédiger une série de tutos sur la programmation et je cherche à réveiller mes réflexes de "vulgarisateur", endormis depuis trop longtemps.
@NSProbleme
Peut-être tu crois que tu as compris comment coder l'algo Caesar mais ton code reste vachement bouleversant, avec beaucoup de conditions compliquées et les noms insensés.
Voice le code, nettoyé et avec les noms qui sont presque autodocumentant ; ce qui t'aidera quand le jour arrive de le revisiter :
Mais, si tu essaies de crypter les caractères accentués, tu verras pourquoi Drake est moi t'avons conseillé d'abandonner cet algorithme qui, franchement, est bien périmé