# Umlaute einfügen in Caesar



## HasiBernd (4. Nov 2015)

Bei einer Unterrichtsaufgabe ergab sich für uns folgendes Problem:

Unser erstelltes Programm tut im Prinzip genau das, was es tun soll. Es verschlüsselt nach dem Caesar Verfahren alles, was zwischen A-Z liegt und dies auch mit der gewünschten Verschiebung. Nur haben wir große Probleme, beim Einfügen der Umlaute (äüö) sowie des ß.
Wir haben es bereits mit der ASCII versucht, allerdings stören uns die verbleibenden Sonderzeichen und restlichen Umlaute, da wir auch rückübersetzen wollen und dass so dann natürlich nicht so recht funktioniert, da wir nicht umkopieren können.
Zudem finden wir es nicht ansehnlich und möchten es vermeiden, kamen aber leider nicht auf eine andere Lösung und diverse Internetbeiträge halfen uns auch nicht wirklich weiter.

*Hier ist nun unser Code (in Komplettfassung) :*

```
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/**
*
* Beschreibung
*
* @version 1.0 vom 07.10.2015
* @author
*/

public class CaesarSatan extends JFrame {
   // Anfang Attribute
   private JTextField jTextField1 = new JTextField();
   private JTextField jTextField2 = new JTextField();
   private JButton jButton1 = new JButton();
   private JNumberField jNumberField1 = new JNumberField();
   private JButton jButton2 = new JButton();
   private JLabel jLabel1 = new JLabel();
   private JLabel jLabel2 = new JLabel();
   private JLabel jLabel3 = new JLabel();
   // Ende Attribute

   public CaesarSatan(String title) {
     // Frame-Initialisierung
     super(title);
     setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
     int frameWidth = 296;
     int frameHeight = 300;
     setSize(frameWidth, frameHeight);
     Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
     int x = (d.width - getSize().width) / 2;
     int y = (d.height - getSize().height) / 2;
     setLocation(x, y);
     setResizable(false);
     Container cp = getContentPane();
     cp.setLayout(null);
     // Anfang Komponenten

     jTextField1.setBounds(72, 48, 150, 20);
     cp.add(jTextField1);
     jTextField2.setBounds(72, 208, 150, 20);
     cp.add(jTextField2);
     jButton1.setBounds(24, 152, 99, 25);
     jButton1.setText("Verschlüsseln");
     jButton1.setMargin(new Insets(2, 2, 2, 2));
     jButton1.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
         jButton1_ActionPerformed(evt);
       }
     });
     jButton1.setBackground(new Color(0xA3B8CC));
     cp.add(jButton1);
     jNumberField1.setBounds(104, 104, 83, 20);
     jNumberField1.setText("");
     cp.add(jNumberField1);
     jButton2.setBounds(168, 152, 99, 25);
     jButton2.setText("Entschlüsseln");
     jButton2.setMargin(new Insets(2, 2, 2, 2));
     jButton2.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
         jButton2_ActionPerformed(evt);
       }
     });
     jButton2.setBackground(new Color(0xA3B8CC));
     cp.add(jButton2);  
     jLabel1.setBounds(8, 48, 62, 20);
     jLabel1.setText("Botschaft:");
     cp.add(jLabel1);
     jLabel2.setBounds(8, 104, 86, 20);
     jLabel2.setText("Verschiebung:");
     cp.add(jLabel2);
     jLabel3.setBounds(8, 208, 62, 20);
     jLabel3.setText("Botschaft:");
     jLabel3.setOpaque(false);
     cp.add(jLabel3);
     cp.setBackground(new Color(0xB8CFE5));
     // Ende Komponenten

     setVisible(true);
   } // end of public CaesarSatan

   // Anfang Methoden
   public void jButton1_ActionPerformed(ActionEvent evt) {
     String geheimtext = "";
     String klartext= jTextField1.getText();
     int verschiebung = jNumberField1.getInt();
     char buchstabe;
     int nummer;
     klartext = klartext.toUpperCase();
     for (int i=0; i < klartext.length(); i++) {
       buchstabe = klartext.charAt(i);
       nummer = (int)buchstabe-(int)'A';  
       if (buchstabe >='A' && buchstabe <='Z') {
         nummer = (nummer + verschiebung + 26) % 26;
       }
       geheimtext = geheimtext + (char)(nummer + (int)'A');
     }
     jTextField2.setText(geheimtext); // TODO hier Quelltext einfügen

   } // end of jButton1_ActionPerformed

   public void jButton2_ActionPerformed(ActionEvent evt) {
     String geheimtext = "";
     String klartext= jTextField1.getText();
     int verschiebung = 26-jNumberField1.getInt();
     char buchstabe;
     int nummer; klartext = klartext.toUpperCase();
     for (int i=0; i < klartext.length(); i++) {
       buchstabe = klartext.charAt(i);
       nummer = (int)buchstabe-(int)'A';
       if (buchstabe >='A' && buchstabe<='Z') {
         nummer = (nummer + verschiebung + 26) % 26;
       }
       geheimtext = geheimtext + (char)(nummer + (int)'A');
     }
     jTextField2.setText(geheimtext);// TODO hier Quelltext einfügen
   } // end of jButton2_ActionPerformed

   // Ende Methoden

   public static void main(String[] args) {
     new CaesarSatan("CaesarSatan");
   } // end of main
} // end of class CaesarSatan
```


_*Wichtig sind in diesem Fall sicherlich nur die Dinge, die wir in die Buttons programmiert haben.
Wir würden uns sehr über hilfreiche Kommentare freuen, da es bei uns im Informatik Unterricht eine eher weniger lehrreiche Phase gab und uns deshalb der letzte Schritt sehr schwer fällt.

Mit freundlichen Grüßen,
zwei verzweifelte Schülerinnen <3
*_


----------



## Dompteur (4. Nov 2015)

Ich würde mir zuerst eine Konstante mit den erlaubten Zeichen anlegen:

```
final String charset = "abcd..xyzäöüß"; // die Buchstaben a-z sowie die 3 Umlaute und das scharfe ß 
final int charsetlen = charset.length(); // diese Konstante ersetzt die Zahl 26 im bisherigen Code.
```
Jetzt brauchst du noch eine Methode, die zu einem Buchstaben die Position im charset bestimmt.
Eine 2. Methode ermittelt aus der Position den Buchstaben.

Dies muss dann noch im bestehenden Code richtig eingebunden werden.


----------



## HasiBernd (5. Nov 2015)

Dankeschön, Dompteur  Mal gucken, ob wir das hinbekommen...


----------



## Flown (5. Nov 2015)

Abgesehen von der Caesar Verschlüsselung, habt ihr den UI Code geschrieben? Der ist stark verbesserungswürdig.


----------



## HasiBernd (11. Nov 2015)

Wenn das Verbesserungswürdig ist, was würdest du denn verbessern? Wir sind ja für alle Verbesserungsvorschläge offen...


----------



## Flown (11. Nov 2015)

Wo fängt man hier an? Also:
- Man leitet nicht von JFrame ab, außer man erweitert dessen Funktion
- Man verwendet sprechende Namen für Objekte und Methoden (lowerCamelCase)
- Man definiert Konstanten nicht mitten im Code sondern als static final Feld
- Man sollte die Java Doku lesen, damit kann man dann ein JFrame schneller zentrieren (`JFrame::setLocationRelativeTo(null);`)
- Allgemein null-Layouts are evil! Außer man setzt das Frame auf einen gewisse Größe und ist statisch in der Größe
- Man erstellt sich sein eigenen ContentPane und setzt ihn dann dem JFrame
- Man setzt Funktionalitäten in Klassen und Methoden um
- Man startet ein AWT/Swing Programm, indem man es in den EDT einreiht
- Man vermeidet unnötige Kommentare im Code
- Man sollte Kommentare mittels JavaDoc schreiben (class Caesar als Beispiel)

Dann sieht das eventuell auch so aus:


Spoiler: Code





```
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;

import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
*
* Beschreibung
*
* @version 1.0 vom 07.10.2015
* @author
*/

public class CaesarUI {
    private final int FRAME_WIDTH = 296;
    private final int FRAME_HEIGHT = 300;
    private final Caesar caesarEncoding = new Caesar();
  
    public CaesarUI(String title) {
        JFrame frame = new JFrame(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
      
        JPanel mainPanel = new JPanel(null);
      
        JTextField plainMessageField = new JTextField();
        plainMessageField.setBounds(72, 48, 150, 20);
        mainPanel.add(plainMessageField);
      
        JTextField encryptedMessageField = new JTextField();
        encryptedMessageField.setBounds(72, 208, 150, 20);
        mainPanel.add(encryptedMessageField);
      
        JFormattedTextField shiftField = new JFormattedTextField(NumberFormat.getIntegerInstance());
        shiftField.setBounds(104, 104, 83, 20);
        shiftField.setValue(0);
        mainPanel.add(shiftField);
      
        JButton encryptButton = new JButton("Verschlüsseln");
        encryptButton.setBounds(24, 152, 99, 25);
        encryptButton.setMargin(new Insets(2, 2, 2, 2));
        encryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                int shift = ((Number) shiftField.getValue()).intValue();
                String message = plainMessageField.getText();
                encryptedMessageField.setText(caesarEncoding.encode(message, shift));
            }
        });
        encryptButton.setBackground(new Color(0xA3B8CC));
        mainPanel.add(encryptButton);
      
        JButton decryptButton = new JButton("Entschlüsseln");
        decryptButton.setBounds(168, 152, 99, 25);
        decryptButton.setMargin(new Insets(2, 2, 2, 2));
        decryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                int shift = ((Number) shiftField.getValue()).intValue();
                String message = plainMessageField.getText();
                encryptedMessageField.setText(caesarEncoding.decode(message, shift));
            }
        });
        decryptButton.setBackground(new Color(0xA3B8CC));
        mainPanel.add(decryptButton);
      
        JLabel plainMessageLabel = new JLabel("Botschaft:");
        plainMessageLabel.setBounds(8, 48, 62, 20);
        mainPanel.add(plainMessageLabel);
      
        JLabel shiftLabel = new JLabel("Verschiebung:");
        shiftLabel.setBounds(8, 104, 86, 20);
        mainPanel.add(shiftLabel);
      
        JLabel encryptedMessageLabel = new JLabel("Botschaft:");
        encryptedMessageLabel.setBounds(8, 208, 62, 20);
        encryptedMessageLabel.setOpaque(false);
        mainPanel.add(encryptedMessageLabel);
      
        mainPanel.setBackground(new Color(0xB8CFE5));
      
        frame.add(mainPanel);
      
        frame.setVisible(true);
    }
  
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CaesarUI("Caesar Cipher");
            }
        });
    }
  
    /**
     * Encoding and decoding of a {@link String} using the
     * <A HREF="https://en.wikipedia.org/wiki/Caesar_cipher">Caesar cipher</a>.
     *
     * @author Flown
     */
    class Caesar {
        /**
         * Standard alphabet in range [a-z]
         */
        public static final String STANDARD_ALPHABET = "abcdefghijklmnopqrstuvwxyz";
      
        private final String alphabet;
      
        /**
         * Creates a new {@code Caesar} object using {@code STANDARD_ALPHABET} as
         * cipher basis.
         */
        public Caesar() {
            this(STANDARD_ALPHABET);
        }
      
        /**
         * Creates a new {@code Caesar} object using provided {@code alphabet} as
         * cipher basis.
         *
         * @param alphabet
         *          cipher basis
         */
        public Caesar(String alphabet) {
            this.alphabet = alphabet;
        }
      
        /**
         * Encodes the given message by shifting every character by the factor
         * {@code shift}.
         * <p>
         * <b>Note:</b> Before encoding the plain message is transformed to a lower
         * case {@link String}. Unknown characters in plain message are not encoded.
         *
         * @param message
         *          plain message
         * @param shift
         *          shift factor
         * @return encoded lower case message
         */
        public String encode(String message, int shift) {
            StringBuilder builder = new StringBuilder();
            for (char c : message.toLowerCase().toCharArray()) {
                int index = alphabet.indexOf(c);
                if (index != -1) {
                    builder
                    .append(alphabet.charAt((alphabet.length() + (index + shift) % alphabet.length()) % alphabet.length()));
                } else {
                    builder.append(c);
                }
              
            }
            return builder.toString();
        }
      
        /**
         * Decodes the given message by shifting every character by the factor
         * {@code shift}.
         * <p>
         * <b>Note:</b> Before decoding the plain message is transformed to a lower
         * case {@link String}. Unknown characters in plain message are not decoded.
         *
         * @param message
         *          plain message
         * @param shift
         *          shift factor
         * @return decoded lower case message
         */
        public String decode(String message, int shift) {
            return encode(message, -shift);
        }
    }
}
```


----------



## David23x (13. Nov 2015)

In deinem Code schreibst du

```
builder.append(alphabet.charAt((alphabet.length() + (index + shift) % alphabet.length()) % alphabet.length()));
```
Würde

```
builder.append(alphabet.charAt((index + shift) % alphabet.length()));
```
nicht reichen?


----------



## Dompteur (13. Nov 2015)

shift kann ja auch negativ sein (=Dekodieren).
Dann kommst du in den negativen Zahlenbereich. Daher musst du alphabet.length() dazuaddieren.
Allerdings hast du recht, dass man sich eine Modulooperation ersparen kann:

```
builder.append(alphabet.charAt( (alphabet.length() + index + shift ) % alphabet.length()));
```


----------



## David23x (13. Nov 2015)

Ach so.


----------



## Flown (16. Nov 2015)

Ein modulo würde ausreichen, wenn `shift < alphabet.length() + index` immer wahr wäre.


----------

