Caesar-Chiffrierung Java?

5 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Bei char-Arrays kannst du halt die nötigen Rechenoperationen auf ASCII-Zeichen einfacher umsetzen, als wenn du versuchst, das direkt in einem String zu machen. Du kannst bei char Werten halt z.B. einfach 'a' + 3 rechnen und kriegst 'd' raus. Bei Strings geht das nicht.

package de.daCypher.exercises;


import java.util.Scanner;


public class Caesar {
	
	// die main-Methode ist hier nur zum testen. Der für dich interessante Teil
	// ist die rotate-Methode
	public static void main(String[] args) {
		System.out.println("Bitte Text eingeben, der ver- und entschlüsselt werden soll.");
		
		String input = new Scanner(System.in).nextLine();
		String encrypted = encrypt(input);
		
		System.out.println("Verschlüsselt: " + encrypted);
		System.out.println("Entschlüsselt: " + decrypt(encrypted));
	}
	
	private static String rotate(String string, int amount) {
		// Eingabestring in Kleinbuchstaben umwandeln und in ein char Array schreiben
		char[] temp = string.toLowerCase().toCharArray();
		
		// Alle Buchstaben im char Array durchgehen
		for (int i = 0; i < temp.length; i++) {
			// Zeichen nur umwandeln, wenn es Buchstaben sind (also keine Zahlen oder Satzzeichen umwandeln) 
			if (temp[i] >= 'a' && temp[i] <= 'z') {
				// Buchstaben um die gewünschte Anzahl verändern
				temp[i] += amount;
				
				// Falls wir bei der Umwandlung über das Ziel hinausgeschossen sind, 
				// vom anderen Ende des Alphabets weitermachen.
				// (Würde auch mit modulo funktionieren, ist aber so wahrscheinlich anfängerfreundlicher)
				if (temp[i] < 'a') {
					temp[i] += 26;
				} else if (temp[i] > 'z') {
					temp[i] -= 26;
				}
			}
		}
		
		// char Array wieder in einen String umwandeln und zurückgeben
		return new String(temp);
	}
	
	private static String encrypt(String string) {
		// Laut Wikipedia soll die Standard-Schrittweite für die Caesar Verschlüsselung
		// drei Buchstaben sein. Falls ihr da was anderes benutzt, musst du das
		// dementsprechend ändern.
		
		return rotate(string, 3);
	}
	
	private static String decrypt(String string) {
		return rotate(string, -3);
	}
}
anna0811 
Fragesteller
 13.11.2020, 14:26

Vielen vielen Dank für die ausführliche Antwort! Dank deiner Erklärung habe ich verstanden warum ich mit Arrays arbeiten soll :) Ich hab nur noch eine Frage: Und zwar darf ich keinen Scanner benutzen (gar keine Imports) und nur Basics anwenden. Die Werte wollen die Professoren festlegen (sprich den zu verschlüsselnden Text und die Anzahl der zu verrückenden Stellen)... Ich habe es bis jetzt immer so gemacht, dass ich in die Main-Methode "System.out.println(NameDerMethode(String, Wert Int)) geschrieben habe, sodass die Werte für meine Methode genutzt wurden. So klappt es aber dieses Mal nicht :(

Wie kann ich es denn hierbei machen, dass der String (zu verschlüsselnder Text) und der Int-Wert (Faktor um den Buchstabe verschoben wird) immer manuell zum Testen verändert werden kann?

0
daCypher  13.11.2020, 14:33
@anna0811

Hier geht es auch so. Die Methoden encrypt und decrypt sind fest auf den Faktor 3 eingestellt, aber die rotate Methode kannst du so aufrufen, wie du es vorschlägst.

System.out.println(rotate("Test", 3));

Du kannst für die Methoden natürlich auch andere Namen benutzen oder in die encrypt und decrypt-Methode ein zusätzliches Argument für den Faktor einsetzen.

1
anna0811 
Fragesteller
 13.11.2020, 14:56
@daCypher

Hmm, also ich habe ergänzt was mir gefehlt hat anhand deiner Erklärung. Allerdings funktioniert mein Programm nicht, obwohl ich keine Fehlermeldungen habe. Den Scanner in der Main-Methode und die Decrypt-Methode habe ich weggelassen, da ich nur verschlüsseln soll und ja keine Imports benutzen darf :( Sorry, ich weiß nicht wie man den Code so einfügt wie du, deswegen mache ich es jetzt so ...

  1. public class Functionality {
  2. public static void main(String[] args) {
  3. System.out.println(encodeCaesar("Ac", 10));
  4. }
  5. public static String encodeCaesar(String s, int val) {
  6. char[] shift = s.toLowerCase().toCharArray();
  7. if (val < 0 || val > 26) { // habe ich eingegeben, da ein leerer String ausgegeben werden soll, wenn Int-Wert unter 0 oder über 26 liegt
  8. return " ";
  9. }
  10. for (int i = 0; i < shift.length; i++) {
  11. if (shift[i] >= 'a' || shift[i] <= 'z') {
  12. shift[i] += val;
  13. }
  14. if (shift[i] < 'a') {
  15. shift[i] += 26;
  16. } else if (shift[i] > 'z') {
  17. shift[i] -= 26;
  18. }
  19. }
  20. }
  21. return new String(shift);
  22. }
  23. /*public static String encrypt(String s) {
  24. return encodeCaesar(s, 3);
  25. } */
  26. // klappt weder mit, noch ohne Encrypt-Methode
  27. }
0
daCypher  13.11.2020, 15:05
@anna0811

In der Zeile 18-20 ist eine schließende Klammer zu viel drin. Und in der Zeile 8 kannst du das Leerzeichen zwischen den Gänsefüßchen rausnehmen, weil ein leerer String und kein einzelnes Leerzeichen als Rückgabewert gewünscht ist.

Ich hab sicherheitshalber nochmal die funktionierende und übersichtlich gemachte Version angehängt:

public class Functionality {
	public static void main(String[] args) {
		System.out.println(encodeCaesar("Ac", 10));
	}


	public static String encodeCaesar(String s, int val) {
		char[] shift = s.toLowerCase().toCharArray();
	
		if (val < 0 || val > 26) {
			return ""; // Ein leerer String ist wirklich ein leerer String, also kein Leerzeichen.
		}
		
		for (int i = 0; i < shift.length; i++) {
			if (shift[i] >= 'a' || shift[i] <= 'z') {
				shift[i] += val;
			}
			
			if (shift[i] < 'a') {
				shift[i] += 26;
			} else if (shift[i] > 'z') {
				shift[i] -= 26;
			}
		}
		return new String(shift);
	}
}

Als Tipp noch: Benutze mehr aussagekräftige Variablennamen. Also als Parameter z.B. nicht s und val, sondern vielleicht inputString und factor.

0
anna0811 
Fragesteller
 13.11.2020, 15:17
@daCypher

Die überflüssige Klammer hatte ich zwischenzeitlich schon gelöscht und das Leerzeichen habe ich entfernt (Hast Recht, leer ist leer :D) und das Programm klappt! Ich hatte in dem Package eine andere fehlerhafte Klasse weswegen die ganze Zeit Error kam...

Nochmals vielen Dank an dich. Mein Problem ist im Moment noch in Programmiersprache zu denken, das muss ich unbedingt noch üben. Weil an sich ist das alles so logisch, nur ich hänge mich dann immer an irgendwelchen Punkten auf. Bin noch absoluter Neuling. Und auch wenn ich mir etliche Videos über Arrays, usw. angeguckt habe, stehe ich am Anfang immer da und weiß nicht wie ich die Aufgabe umsetzen soll.

0
daCypher  13.11.2020, 15:20
@anna0811

Ja, ich hatte bei Java am Anfang auch Probleme. Lag aber auch daran, dass ich das in der Ausbildung lernen musste und wir einen absolut unfähigen Lehrer hatten und ohne Programmierumgebung in einem einfachen Texteditor programmieren mussten. Wenn du da nicht mal gesagt kriegst, dass Java sehr penibel auf Groß-/Kleinschreibung achtet und "String" groß geschrieben werden muss, während "int" klein geschrieben werden muss, verzweifelst du irgendwann.

Wirklich gelernt hab ich es erst, als ich mich spaßeshalber bei CodinGame.com angemeldet hab. Da lernt man auf spielerische Weise Java und muss am Anfang nur einzelne Zeilen in einem vorgefertigtem Programm ergänzen. Vielleicht kannst du dir das ja mal anschauen.

0

Strings sind in Java unveränderlich ("immutable"). Das ist eine sehr gute Sache, bedeutet aber eben auch, dass eine vermeintliche Änderung eines bestehenden Strings nur über das Erzeugen eines neuen Strings möglich ist.

Möglicherweise will man euch nahelegen, dass ihr für das Erzeugen des chiffrierten Strings daher ein char-Array verwenden sollt. Das ist aber auch nur geraten - zwingend nötig ist es nicht; für das kumulative Bauen von Strings gibt es eigentlich den StringBuilder.

Nun ja, bei einer Cäsar-Chiffre "rotierst" du ja einfach nur die entsprechenden Buchstaben.

Man KÖNNTE jetzt die Aufgabenstellung auf zwei Wegen verstehen:

  • erstelle aus dem Original-String ein char-Array, iteriere über jeden Wert und addiere den Offset drauf (und stell sicher, dass du im korrekten Bereich bleibst).
  • erstelle ein Char-Array mit allen Zeichen von a bis z. Berechne für jeden Char des originalen String den Index, rechne den Offset (modulo 26) drauf und füge den neuen, verschlüsselten Char dem Ergebnis hinzu.

Hm - die Caesar-Chiffrierung ist ja einfach nur eine rollierende Buchstabenvertauschung (ROT18 soviel ich weiß). Ich würde das über den ASCII Code machen.

Ca. so.

Ist aber in python

import string


a = list(string.ascii_lowercase)
word = 'halLo'
shift = 1
b = ''.join([a[(a.index(c)+shift)%26] if(c.islower()) else a[(a.index(c.lower())+shift)%26].upper() for c in word])
print(b)
Woher ich das weiß:Studium / Ausbildung – Informatikstudent