Cäsar-Veschlüsselung

Aloushi

Mitglied
Hallo kann mir jemand mit dieser Aufgabe helfen?
Einige Ansätze habe ich bereits, jedoch weiß ich nicht, wie ich diese zusammenhängen soll.

Meine Ansätze:
Klasse implementiert ✔️
char[] erstellt mit dem Alphabet (in Form einer for Schleife?) ✔️
while Schleife erstellt (sodass ein leerer String ausgegeben wird, falls int < 0 oder > 26 ist) ✔️
Als String Manipulation toUpperCase verwenden (jedoch keine Ahnung wo ich ihn einsetzten soll) ✔️





Implementieren Sie eine statische-public Methode mit dem Namen "encodeCaesar" in der Klasse "Functionality.java", welche einen Text mithilfe der Cäsar-Veschlüsselung chiffriert.

Signatur: encodeCaesar(String s, int val) : String

Informationen zum Prinzip finden Sie zum Beispiel hier: https://de.wikipedia.org/wiki/Caesar-Verschlüsselung.

Die Methode bekommt als Eingabeparameter einen String-Wert und einen Integer-Wert. Die Buchstaben (Character) aus dem String-Wert sollen um den Integer-Wert verschoben werden.
Der einfachheitshalber können Sie davon ausgehen, dass nur Buchstaben und keine Leer-, Ziffer- oder Sonderzeichen vorhanden sind.
Der String-Wert soll in Kleinbuchstaben umgewandelt werden, bevor die Verschlüsselung durchgeführt wird.

Die Methode soll wieder einen String zurückgeben, bei dem jeder Buchstabe entsprechend des angebenen Integer-Wertes verschoben wurde.
Beispiel: encodeCaesar("Ac",3) gibt "df" zurück.
Wenn der mitgegebene Integer-Wert kleiner als 0 oder größer als 26 ist, soll ein leerer String zurückgegeben werden.

Verwenden Sie in Ihrer Lösung String-Manipulationen und Character-Arrays (char[]).
Die Verwendung von externen Bibliotheken oder anderen Inhalten, die noch nicht in dieser Veranstaltung behandelt wurden, sind untersagt.

Hinweis:
Der größte ASCII-Wert eines Kleinbuchstabens ist 'z' = 122. Wenn man durch Verschiebung über diesen Wert kommt, fängt man von vorne beim 'a' wieder an.
 

jono

Top Contributor
Der String soll ja am Ende in Kleinbuchstaben ausgegeben werden, deshalb dann s.toLowerCase();
Den String dann einem Char-Array zuzuweisen ist dann auch noch machbar für mich. Schwieriger wird es für mich
Java:
 "Der größte ASCII-Wert eines Kleinbuchstabens ist 'z' = 122. Wenn man durch Verschiebung über diesen Wert kommt, fängt man von vorne beim 'a' wieder an."
dieses umzusetzen...
 

jono

Top Contributor
Die Rechenvorschrift kann ich überhaupt nicht nachvollziehen. Dass 97 der ASCII Wert für a ist weiß ich ja.. Aber Mod... Verstehe ich nicht
 

Meniskusschaden

Top Contributor
Die Rechenvorschrift kann ich überhaupt nicht nachvollziehen.
Die ist so meines Erachtens noch nicht ganz richtig.
mod steht für den modulo-Operator zur Ermittlung des Divisionsrestes.

Vielleicht ist es einfacher, wenn du erst einmal so tust, als hätten die Buchstaben 'a' bis 'z' die Codes 0 bis 25 und dafür die Rechenvorschrift entwickelst. Wenn du die hast, kannst du sie relativ leicht so anpassen, dass sie im Bereich von 97 bis 122 funktioniert.
 

jono

Top Contributor
Java:
for (int i = 0; i < char1.length; i++) {
            if(char1[i] > 122) {
                char1[i] - ;
            } else {
                char1[i] += val;
            }
            
            
        }
Ich hätte es jetzt hier mal so gemacht, ich möchte ja aber 25 an der Stelle i wieder abziehen, deshalb das "-". Da das aber nicht klappt einfach eine Zahl von char1 zu subtrahieren, ist mir der Lösungsweg mit dem Divisionrest nicht ganz einleuchtend.
 

mrBrown

Super-Moderator
Mitarbeiter
Ich hätte es jetzt hier mal so gemacht, ich möchte ja aber 25 an der Stelle i wieder abziehen, deshalb das "-". Da das aber nicht klappt einfach eine Zahl von char1 zu subtrahieren, ist mir der Lösungsweg mit dem Divisionrest nicht ganz einleuchtend.

Der Einfachheitshalber nutz ich einfach auch mal 0 für A und 25 für Z:

0-25 müssen ja gleich bleiben und dürfen nicht verändert werden:
0 % 26 = 0, ..., 25 % 26 = 25

Ab 26 soll es wieder bei 0 (=A) anfangen:
26 % 26 = 0, 27 % 26 = 1...
 

jono

Top Contributor
Gut, dass verstehe ich...
Wie setze ich das jetzt um? Wenn ich überlege kommt mir folgendes in den Sinn:
Wenn das Char-Array an der Stelle i + den Integer-Wert "val" > 122 beträgt, dann muss man ja schonmal von vorne anfangen, nämlich bei 97.
Java:
for (int i = 0; i < char1.length; i++) {
            if(char1[i] % 122 == 0 || char1[i] % 122 > 0) {
                ;
            } else {
                char1[i] += val;
            }
            
            
        }
Ich möchte natürlich die for-Schleife verwenden, um dass Array an i-ten Stelle durchlaufen zu können.
if-Bedingung: Wenn das Array an der i-ten Stelle einer der oben genannten Bedingungen entspricht, dann muss ja auf "a" also 97 zurückgesetzt werden...
Das else ergibt sich ja relativ schnell für mich...
Habe aber wirklich Probleme dabei auf 97 zurückzusetten..
 
K

kneitzel

Gast
Ich verstehe nicht, wo das Problem ist. Schreib den Weg doch einmal in eigenen Worten genau auf.

Also erläutere mir:
- Wie machst Du aus einem großen Buchstaben einen kleinen? (Inkl. Erkennung natürlich)
- Wie bekommst Du die Position im Alphabet und wie definierst Du diese?
- Wie kannst Du dann dieses Verschieben machen, also eine neue Position bekommen?
- Wie kannst Du die neue Position prüfen? Und was machst Du, wenn die Position ungültig ist?
- Wie bekommst Du nun den Buchstaben der neuen Position?

Beschreibe es ausführlich und zwar so ausführlich, dass andere Deiner Beschreibung folgen können ohne die Aufgabe zu kennen!

Das ist der erste Schritt, den Du schaffen musst. Die Übersetzung in Java dürfte dann keine Probleme mehr bereiten vermute ich.
 

jono

Top Contributor
Wie machst Du aus einem großen Buchstaben einen kleinen? (Inkl. Erkennung natürlich)
Java:
s.toLowerCase();
Was aber genau meinst du hier mit Erkennung?

- Wie bekommst Du die Position im Alphabet und wie definierst Du diese?
Man wandelt den String ja in ein Char-Array um, sodass die einzelnen Zeichen verschlüsselt werden. Die Position der Buchstaben im Alphabet sind ja sozusagen durch die ASCII Tabelle festgelegt.

Wie kannst Du dann dieses Verschieben machen, also eine neue Position bekommen?
Das Verschieben: Durch Addition des Integer-Eingabeparameters zur i-ten Stelle des char-Arrays. Sprich eine for-Schleife und in der Anweisung:
Java:
 char1[i] += val;
Wie kannst Du die neue Position prüfen? Und was machst Du, wenn die Position ungültig ist?
Mit einer if-Anweisung bzw. Bedingung.
Aber genau hier stockt es. Ich möchte ja sagen:
Wenn Die Verschiebung >=122, dann soll ja von vorne bei "a" angefangen werden, also bei der 97, die ja für das "a" steht. Mein trivialer Ansatz hier:
Java:
If(char1[i] += val >= 122) { // Dann soll wieder bei a angefangen werden
Wie ich hier korrekt mit dem Modulo arbeiten muss, ist mir nicht klar.
Mir ist bewusst, dass das so nicht geht in den Klammern. Man müsste es vorher so deklarieren..
Wenn char += val % 122 >= 0, dann soll beginnend bei 97 bzw. a angefangen werden.

Wie bekommst Du nun den Buchstaben der neuen Position?
Den bekomme ich, in dem ich das Char-Array wieder in ein String umwandeln kann..wenn ich die Frage richtig verstanden habe. Wenn ja, dann sollte es kein Problem sein.
 

mihe7

Top Contributor
Gut, dass verstehe ich...
Wäre dem so, dann hättest Du die Aufgabe bereits gelöst.

Was aber genau meinst du hier mit Erkennung?
Du kannst ja nicht blind 32 auf einen beliebigen ASCII-Wert addieren sondern musst vorher prüfen, ob es sich überhaupt um einen Buchstaben handelt, wenn ja, in welchem Bereich er liegt und erst dann kannst Du sagen: ok, das ist ein Großbuchstabe zwischen A und Z, da kann ich 32 addieren, um den entsprechenden Kleinbuchstaben zu erhalten. Du verwendest aber toLowerCase() - da wird das alles für Dich übernommen.

Die Position der Buchstaben im Alphabet sind ja sozusagen durch die ASCII Tabelle festgelegt.
Das ist zu ungenau und diese Ungenauigkeit ist das Problem. Beantworte die Frage von @kneitzel ganz konkret. Sag, was Du machen musst, um vom ASCII-Wert auf die Position des Buchstabens im Alphabet zu kommen.
 

jono

Top Contributor
Du kannst ja nicht blind 32 auf einen beliebigen ASCII-Wert addieren
Der ASCII Wert muss größer gleich 97 sein. Also char >= 97;

Das ist zu ungenau und diese Ungenauigkeit ist das Problem. Beantworte die Frage von @kneitzel ganz konkret. Sag, was Du machen musst, um vom ASCII-Wert auf die Position des Buchstabens im Alphabet zu kommen
Der ASCII Wert stellt doch die Position eines Buchstabens dar?
 

jono

Top Contributor
Nein, der ASCII-Wert müsste zwischen 65 und 92 liegen (A-Z), aber das spielt keine Rolle, weil Du ja toLowerCase() verwendest.
Ja aber das kleine a steht ja für 97.

Steht das 'a' an 97. Stelle im Alphabet?!?
Nein, natürlich nicht. Die Differenz zwischen 122 und z.B. 115 wäre 7. Das heißt: Subtrahiert man 7 von der 26, so erhält man 19. Somit erhält man die Position des Buchstabens im Alphabet.
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Ja aber das kleine a steht ja für 97.
Es ging um die Umwandlung eines Großbuchstabens in einen Kleinbuchstaben, nicht darum, ob das 'a' den ASCII-Code 97 hat. Aber nun zum dritten Mal: die Prüfung braucht Dich nicht weiter zu interessieren, da Du toLowerCase() verwendest.

Nein, natürlich nicht. Die Differenz zwischen 122 und z.B. 115 wäre 7.
Langsam, langsam.... Im ersten Schritt ging es darum, Großbuchstaben in Kleinbuchstaben umzuwandeln. Aus "JONO" wird also "jono", was den ASCII-Codes 106, 111, 110, 111 entspricht.

Jetzt ist die Frage: wie ermittelst Du aus der 106 die Position des 'j' im gewöhnlichen Alphabet?
 

jono

Top Contributor
Damit: Ja aber das kleine a steht ja für 97. Wollte ich auch nur nochmal sagen, dass ja schon lower Case verwendet wird ,weil der Einwand mit den Großbuchstaben auch nicht nötig war.
Es ging um die Umwandlung eines Großbuchstabens in einen Kleinbuchstaben, nicht darum, ob das 'a' den ASCII-Code 97 hat. Aber nun zum dritten Mal: die Prüfung braucht Dich nicht weiter zu interessieren, da Du toLowerCase() verwendest.

Die Differenz zwischen 122 und z.B. 115 wäre 7. Das heißt: Subtrahiert man 7 von der 26, so erhält man 19. Somit erhält man die Position des Buchstabens im Alphabet.
Genau so geht das auch mit dem j. 122-106 = 16 ( 26-16=10) also ist das j an 10. Stelle im Alphabet.
 

mihe7

Top Contributor
Genau so geht das auch mit dem j. 122-106 = 16 ( 26-16=10) also ist das j an 10. Stelle im Alphabet.
Das ist aber schon von hinten durch die Brust ins Auge. Hinzu kommt, dass wir 0-basierte Position im Alphabet (sozusagen den Index) haben wollen. Bevor Du da jetzt rumrechnest: zieh einfach 97 ab, dann erhältst Du für das 'a' die 0 und für das 'z' die 25 :)

Für das 'j' würdest Du also 9 erhalten. Jetzt führst Du mal eine Verschiebung durch. Da kann es nun zum Problem kommen, dass Du über 25 hinauskommst. Und an der Stelle verwendest Du dann den Modulo-Operator (%).
 
K

kneitzel

Gast
Wobei ich diese magischen Zahlen nicht verwenden würde. Sorry, aber 97, 122, ... Das ist doch nicht wirklich intuitiv zu verstehen.
Ein char ist für Java auch nur eine Zahl. Also wenn ihr vom "Ascii Wert" von a redet, dann könnt ihr einfach 'a' verwenden. Oder für das große A dann halt 'A'.

Wenn ihr String.toLowerCase nutzen dürft, ist das ok, aber ansonsten kann man einfach prüfen ob das Zeichen im Bereich 'A' - 'Z' ist um dann 'A' abzuziehen und 'a' zu addieren um ein Lowercase Zeichen zu bekommen.

Und bei der Berechnung ist Dir das immer noch nicht ganz klar wie mir scheint.
Das Alphabet ist sozusagen in einem Array
a, b, c, d, ..., z
mit a an [0], b an [1], u.s.w.
Also ist die Berechnung lediglich das Zeichen - 'a'.
'a' - 'a' = 0:
'b' - 'a' = 1;
...
Das ist ja die Berechnung, um an die Position zu kommen. Also nicht noch Anzahl der Zeichen minus dieser Zahl (oder was dann dieses 26-10 sein sollte!)

Die neue Position ist der Ort + Verschiebung.
Dann kommt die Bereichsgrenze incl. evtl. notwendiger Verschiebung. Da kann man modulo verwenden oder einfach ein if - das ist evtl. einfacher für Dich zu verstehen.
Und dann am Ende kommt die Verschiebung zurück, denn 0 soll zum 'a' werden und so. Daher einfach wieder +'a'



Und wenn man sich dies anschaut: Die Verschiebung braucht man nicht zwingend. Man hat oben in den Schritten das -'a' und am Ende das +'a'. Und wenn man eine if Anweisung statt modulo verwendet hat: Da hat man als Grenze 'z'-'a'.
Daher bietet es sich wirklich an, auf dieses "Verschieben" zu verzichten und alles anzupassen:

Dann hat man also den Bereich mit dem lowerCase.
Dann hat man ein Zeichen von 'a' - 'z' (kann man noch prüfen um ggf. eine Fehlermeldung auszugeben).
Zu dem Zeichen kommt die Verschiebung dazu.
Prüfung: Wenn Zeichen > 'z' dann wird die Anzahl der Zeichen ('z' - 'a' + 1) abgezogen.
Und schon ist man fertig - und hat eine Lösung, die ich als gut lesbar ansehen würde, denn die checks sind klar und deutlich ebenso wie die Operationen (So ein 'z' - 'a' + 1 würde ich aber als AnzahlZeichen oder so speichern...).

Ach ja: Aufgabe noch genau prüfen - nicht dass Du irgendwelche Checks vergisst, die da klar gefordert sind :)
 

jono

Top Contributor
Und bei der Berechnung ist Dir das immer noch nicht ganz klar wie mir scheint.
Das Alphabet ist sozusagen in einem Array
a, b, c, d, ..., z
mit a an [0], b an [1], u.s.w.
Das verstehe ich nicht ganz. Wie bekomme ich denn das Alphabet in das Array?
Also ist die Berechnung lediglich das Zeichen - 'a'.
'a' - 'a' = 0:
'b' - 'a' = 1;
...
Das ist ja die Berechnung, um an die Position zu kommen. Also nicht noch Anzahl der Zeichen minus dieser Zahl (oder was dann dieses 26-10 sein sollte!)
Da 'a' der erste Buchstabe im Alphabet ist, ist er im Array an [1], das ist ja klar.
Aber warum möchte man jetzt:
'b'-'a' = 1;
'c'-'a' = 2;
...
Ich muss doch gar nicht an die Position kommen. Es ist doch einfach nur wichtig:
Java:
if (arr[i] + val > 122) {
// Dann soll man wieder um die Alphabetläne 26 subtrahieren, um eine Verschiebung über 122 wieder beim 'a' beginnen zu lassen.
}
bzw.
Java:
} else {
arr[i] + val
zu rechnen. Man möchte ja nur verschieben um den Integerwert und dann den Wert herausbekommen, also z.B. 106 für 'j' + 4 = 110, woraus dann ein 'n' werden soll.
Und dann am Ende kommt die Verschiebung zurück, denn 0 soll zum 'a' werden und so. Daher einfach wieder +'a'



Und wenn man sich dies anschaut: Die Verschiebung braucht man nicht zwingend. Man hat oben in den Schritten das -'a' und am Ende das +'a'. Und wenn man eine if Anweisung statt modulo verwendet hat: Da hat man als Grenze 'z'-'a'.
Daher bietet es sich wirklich an, auf dieses "Verschieben" zu verzichten und alles anzupassen:
Aus 0 soll 'a' werden ? Aus 97 soll a werden hätte ich jetzt gedacht. Ich möchte ja mit den ASCII-Werten arbeiten, da ich diese ja durch das char-Array bekomme. Kann sein das ich vielleicht auch etwas missverstehe..
Was meinst du mit "die Verschiebung braucht man nicht zwingend". Eine Verschiebung findet in allen Fällen statt, darum geht es doch in der Aufgabe. Verstehe halt überhaupt nicht, was du mir damit konkret sagen möchtest.
Prüfung: Wenn Zeichen > 'z' dann wird die Anzahl der Zeichen ('z' - 'a' + 1) abgezogen.
Das ist hier ist ja prinzipiell so zu implementieren:
Java:
for (int i = 0; i < arr.length; i++) {
            if (arr[i] + val > 122)
                res[i] = ( arr[i] + val - 26);
Hiermit hätte sich die Problemlösung doch schon erledigt, verstehe nicht wieso du dieses 'b' - 'a' usw. mit einbeziehst...
 

jono

Top Contributor
Das ist ja die Berechnung, um an die Position zu kommen.
Es kann sein, dass die Frage etwas auf Unverständnis stößt.
Aber wieso soll ich denn auf die Position kommen? Das wird mir hier auch nicht ersichtlich. Ich meine es ist ja klar, dass a an [0]- Stelle ist, aber weshalb sollte ich das ermitteln, das ergibt sich ja daraus, dass jedem Kleinbuchstaben ein ASCII-Wert zuzuweisen ist, der ja schon die Position prinzipiell vordefiniert, wodurch ich diese Ermittlung doch gar nicht benötige..
 

temi

Top Contributor
Das verstehe ich nicht ganz. Wie bekomme ich denn das Alphabet in das Array?
Das sollte nur illustrieren, das 'a' = 0 und 'b' = 1 usw.
Da 'a' der erste Buchstabe im Alphabet ist, ist er im Array an [1], das ist ja klar.
Ne, wenn dann an [0]
Aber warum möchte man jetzt:
'b'-'a' = 1;
Das soll zeigen, dass man auch mit chars rechnen kann oder z.B. Vergleiche machen.
 
K

kneitzel

Gast
@jono: Die Frage ist doch, wie Du Dir das vorstellst. Es gibt kein Array mit Elementen, aber das kann man sich denken.
Das man es nicht zwingend braucht habe ich ja in meinem Code auch geschrieben....

Da aber in dem Thread der Modulo Operator angesprochen wurde, war ich von dieser Idee ausgegangen. Denn da wird das wichtig, sonst kommt man zu einem falschen Ergebnis.

Aber dass diese Verschiebung nicht sein muss habe ich ja auch explizit geschrieben. Die Lösung, die ich favorisiere, entspricht wohl deiner Lösung, nur eben ohne diese magic numbers.
 

mihe7

Top Contributor
Aber wieso soll ich denn auf die Position kommen? Das wird mir hier auch nicht ersichtlich. Ich meine es ist ja klar, dass a an [0]- Stelle ist, aber weshalb sollte ich das ermitteln, das ergibt sich ja daraus, dass jedem Kleinbuchstaben ein ASCII-Wert zuzuweisen ist, der ja schon die Position prinzipiell vordefiniert, wodurch ich diese Ermittlung doch gar nicht benötige..
Es gibt ja grundsätzlich verschiedene Wege, das Problem zu lösen. Einer davon ist die Brechstange, die es in verschiedenen Abstufungen gibt: Du verschiebst das Zeichen um den gewünschten Wert und so lange es sich außerhalb des gültigen Bereichs bewegt, verschiebst Du es um 26 Stellen in die richtige "Richtung", bis es sich im gültigen Bereich befindet. Die Brutalität der Brechstange kann man danach unterscheiden, ob man mit Zeichen ('a', 'z' usw.) oder mit ASCII-Werten (97, 122, usw.) arbeitet.

In dem Fall stellt man sich meist übereinander liegender, linear angeordnete Alphabete vor, z. B.
Code:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
EFGHIJKLMNOPQRSTUVWXYZABCD
Oben wäre das Ausgangsalphabet und unten das Zielalphabet - zum Chiffrieren. Auf das Zielalphabet kommt man, wenn man die Buchstaben des originalen Alphabets um vier Stellen nach links verschiebt.
Code:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
Allerdings muss man den links "überstehenden Teil" gedanklich rechts wieder anfügen.
Code:
    EFGHIJKLMNOPQRSTUVWXYZABCD
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
Das entspricht dem Weg mit der Brechstange und etwas komplizierter wird es, wenn die Buchstaben - wie im Fall von ASCII - zwar nacheinander auftreten aber sich irgendwo zwischen anderen Zeichen befinden. Schon deswegen empfiehlt es sich, sich auf das Alphabet zu beschränken und das 'a' abzuziehen.

Die andere Überlegung ist, sich die Buchstaben auf einem Ring vorzustellen, den man einfach weiterdreht, z. B.
caesar.gif
In der Mitte sind die Indizes angegeben, der erste Ring entspricht dem Quellalphabet und der äußere Ring dem Zielalphabet. Hier wurde einfach der äußere Ring ebenfalls um vier Buchstaben gegen den Uhrzeigersinn gedreht.

Der Witz beim Ring ist: er hat keinen Anfang und kein Ende. Ein solcher Ring lässt sich eben über den Modulo-Operator simulieren. Das ist der rechnerische und weit elegantere Weg. Hier ist es natürlich Pflicht, sich auf das Alphabet zu beschränken und nicht irgendwo wild in ASCII rumzufuhrwerken.

Ist die Sache nun klar?
 

Ähnliche Java Themen

Neue Themen


Oben