Caesar verschlüsselung, problem?

3 Antworten

Schau Dir mal in der ASCII-Tabelle an, wie die Schriftzeichen numeriert sind. Das Alphabet beginnt nicht bei 0. Das große A hat die Nummer 65.

http://www.asciitable.com/

Diese 65 mußt Du berücksichtigen, wenn Du die Verschiebung vornimmst, und zwar einmal, bevor Du den Offset hinzuaddierst und die Modulo-Operation ausführst, und hinterher noch einmal:

int verschiebung = (charArray[i] - 65 + offset)%26 + 65;

ralphdieter  06.01.2017, 12:24

Damit bildest Du z.B. 'G' (71) und 'a' (97) auf den gleichen Wert ab.

0
Franz1957  06.01.2017, 12:36
@ralphdieter

So ist es. Mit kleinen Buchstaben kommt dieser Algorithmus nicht klar, mit Umlauten schon gar nicht, und was noch wichtiger ist: noch nicht einmal mit dem Leerzeichen.

Es müßte oben eigentlich heißen: "Zu verschlüsselnden Text eingeben (nur Großbuchstaben, keine Leerzeichen):"

Aber das kann man nicht alles auf einmal erklären.

1

Im Zeichensatz sind die ersten 26Zeichen einfach keine Buchstaben.

Jeder Zeichensatz hat mindestens 256 Zeichen.

tom1stein  29.10.2018, 06:14

ASCII hat nur 127 Zeichen - also nicht jeder Zeichensatz hat 256 Zeichen. Und das Null-Zeichen ist häufig (z.B. in C) kein Zeichen im eigentlichen Sinne, also bleiben 255 Zeichen. Ansonsten stimmt obige Lösung für die 26 Buchstaben des Alphabets, aber ohne Umlaute etc.

Sonst sind es am Computer die ersten 32 Zeichen (0-31), welche Sonderzeichen (z.B. 8=Tabulator, 10=Zeilenvorschub, 13=Zeilenrücklauf) darstellen und die daher nicht einfach ausgegeben werden dürfen. Danach kommen die Ziffern, die will man sicher auch kodieren.

Also vorher sicherstellen, dass kein Zeichen < 32 oder > 255 eingegeben wurde, und dann:

int verschiebung = (charArray[i] - 32 + offset)%255 + 32;

(Nur um dieser Frage nach 2 Jahren endlich eine allgemeine funktionierende Antwort zu verpassen)

0

Dein Problem liegt hier:

int verschiebung = (charArray[i] + offset)%26;

Jedes Zeichen ist ein UTF-16 Code zwischen 0 (='\u0000') und 65535 (='\uffff'):

  • Die Werte 0-31, 127, und 128-159 sind Steuerzeichen (Tabulator, Zeilenvorschub, Bildschirm löschen, ...). Diese solltest Du nicht verschlüsseln.
  • Zwischen 32 und 126 liegen die ASCII-Zeichen, die jedes Terminal darstellen kann. Diesen Bereich kann man problemlos verschlüsseln. Dabei können Buchstaben in Sonderzeichen umgewandelt werden. Willst Du ausschließlich Buchstaben codieren, beschränke Dich auf die Teilbereiche 'A'-'Z' (65-90) und 'a'-'z' (97-122).
  • Zwischen 160 (='\u00a0') und '\ud7ff' liegen weitere Zeichen wie Umlaute, chinesische Zeichen, Symbole. Was davon angezeigt werden kann, hängt stark vom Terminal und den installierten Fonts ab. Beim Verschlüsseln riskierst Du, dass gängige Zeichen (ä⇒ß±µ²) in unlesbare Zeichen umgewandelt werden. Das erschwert das Debuggen.
  • Ab '\ud800' wird's gefährlich, denn je zwei solcher Codes bilden zusammen ein (sehr seltenes) Zeichen, und nicht jede Kombination ist zulässig. Ich würde solche Codes auf keinen Fall umwandeln.

Du brauchst also unbedingt eine Fallunterscheidung. Dazu würde ich eine Funktion für ein einzelnes Zeichen schreiben:

char verschlüssle(char c, int offset) {
if (c < ' ') // Steuerzeichen
 return c;

if (c < 'A') // ASCII: Sonderzeichen, Ziffern
return c;

if (c <= 'Z') { // ASCII: A-Z
c += offset;
if (c > 'Z') c -= 'Z'-'A'+1; // oder: -=26
return c;
}
if (c < 'a') // ASCII: Sonderzeichen
return c;

  if (c <= 'z') { // ASCII: a-z
c += offset;
if (c > 'z') c -= 'z'-'a'+1; // oder: -=26
return c;
}


 return c; // 127 und non-ASCII
}

In Deiner Schleife schreibst Du dann nur noch:

  cryptArray[i] = verschlüssle(charArray[i], offset);