Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Javakurs/Übungsaufgaben/Cäsar-Chiffre/Musterlösung


/* Decodes texts having been encoded with caesar */




import java.io.*;


public class Caesar {


     public static void main(String arg[])

   {



    int menuCase;

    String text= "";
    String textState= "nothing loaded";
    String output= ""; /*will always be shown under menu*/
    int key;


    do

    {

     System.out.println("[1] load text");
     System.out.println("[2] show text");
     System.out.println("[3] save text");
     System.out.println("[4] encrypt text");
     System.out.println("[5] decrypt text without key");
     System.out.println("[6] decrypt text with key");
     System.out.println("[7] quit");
     System.out.println( );
     System.out.println("text state: ["+ textState +"]");

     System.out.println( );
     System.out.println( output );

     System.out.print("input: ");

     String s= readln();

     menuCase= Integer.parseInt(s);



     switch (menuCase) {

        case 1:

               {

                  System.out.print("filename: ");

                  String fileIn= readln();


                  text= readFile(fileIn);
 
                  output = "";
                  textState= "loaded";

                  break;

               }

        case 2: 
               {
                  output= text;
                  break;
               }
        case 3: 
               {
                  System.out.print("filename: ");

                  String fileName= readln();

                  String[] fileToSave= {text};
                  writeArrayToFile( fileName, fileToSave );

                  output = "";
                  break;
               }
        case 4:
               {
                 System.out.print("key: ");
                 key= Integer.parseInt(readln());

                 text= encryptCaesar(text, key);

                 output = "";
                 textState= "encrypted";
                 break;
               }
        case 5:

               {
                 if( determineKoinzidenzindex(text) < 0.06 ) {
                   output= "Text might not be Caesar encrypted! ";
                 }


                 key= findKeyCaesar(text);

                 text= decryptCaesar(text, key);
 
                 output= "key is: "+ key;
                 textState= "decrypted";


                 break;

               }
        case 6:

               {
                 System.out.print("key: ");
                 key= Integer.parseInt(readln());

                 text= decryptCaesar(text, key);

                 output = "";
                 textState= "decrypted";


                 break;

               }

       }//switch


   }while(menuCase!=7);

  } //main


  /* reads in a text from console */

  public static String readln() {


    BufferedReader consoleLine =

    new BufferedReader(new InputStreamReader(System.in));

    String input = null;

    try {

      input = consoleLine.readLine();

    } catch (IOException e) {

      e.printStackTrace();

    }

      return input;

  }


  /**

   * Schreibt einen String-Array in eine Datei. 

    * @param filename : Pfad zu der Datei in Form eines Strings,
                        also z.B. "hallo.txt" oder "/etc/fstab", ...
    * @param data String-Array: welches in die angegebene Datei 
                                geschrieben werden soll.
    * @return
    */

  public static boolean writeArrayToFile(String filename, 
                                         String[] data   ) {

    BufferedWriter bufferedWriter;

    try {

      // Datei zum schreiben oeffnen

      bufferedWriter= new BufferedWriter(

           new OutputStreamWriter( new FileOutputStream(filename)) );

		

    // Array Elementenweise in Datei schreiben
    for (int i = 0; i < data.length; i++) {

      bufferedWriter.write(data[i]);
      bufferedWriter.newLine();

    }

    bufferedWriter.flush();
	

    } catch (Exception e) {
      // Fehlerbehandlung

      e.printStackTrace();
      return false;

    }

      return true;		
  }



  /* reads in a text */

  public static String readFile( String fileName ) {

    
    String text= "";


    try {

      FileReader file = new FileReader (fileName);

      BufferedReader buff = new BufferedReader(file);


      while ( true ) {

        String line = buff.readLine();

        if ( null == line ) {

             break;

        } else {

          text+= line;

        }

      }


     buff.close();


    } catch (IOException e) {

      System.out.println( e.toString() );

    }

   return text;

  }

                                                                   
  /* takes out punctuation and sets all letters to lower case */

  public static String takeOutPunctuation( String origin ) {


   String originLowCase= origin.toLowerCase();
   String text= "";


   for ( int i= 0; i<originLowCase.length(); i++ ) {
     /* filtering signs 'a' to 'z' using ASCII numbers */

     if (   (originLowCase.charAt(i)>= 'a') 
         && (originLowCase.charAt(i)<= 'z') )

     text+= originLowCase.charAt(i);
   }


   return text;

  }







  public static int[] frequencyAnalysis( String text ) {

    /* holds frequency of chars a-z, last digit (index 26) is total 
     * number of chars in text*/

    int[] chr= new int[27];  



    for ( int j= 0; j< text.length(); j++ ) {

      chr[ text.charAt(j) - 'a' ]++;

      chr[26]++;

    }


   return chr;

  }


  /*see also: http://de.wikipedia.org/wiki/Koinzidenzindex */  

  public static double determineKoinzidenzindex( String text ) {

    text= takeOutPunctuation( text );


    int cnt= 0; 
    double kindex= 0;

    /* holds frequency of chars a-z, last digit (index 26) is total 
     * number of chars in text*/

    int[] chr= frequencyAnalysis(text);


    /* chr.length-1 remember: last digit holds number of chars */

    for ( int k= 0; k< chr.length-1; k++ ) {

      kindex+= ( ((double) chr[k]/chr[26])*((double) chr[k]/chr[26]));

    }



    return kindex;

  }

  /* count the number of nigramms and trigramms  in a german text*/

  public static int germanText( String text ) {

  

    int cntbitri= 0; //counter for bi- and trigramms

    
    /* count bigramms */

    for ( int i= 0; i< text.length()-1; i++ ) {

        if (

            (text.substring(i, i+2).equals("er"))

            ||(text.substring(i, i+2).equals("en"))

            ||(text.substring(i, i+2).equals("ch"))

            ||(text.substring(i, i+2).equals("de"))

            ||(text.substring(i, i+2).equals("ei"))

            ||(text.substring(i, i+2).equals("nd"))

            ||(text.substring(i, i+2).equals("te"))

            ||(text.substring(i, i+2).equals("in"))

            ||(text.substring(i, i+2).equals("ie"))

            ||(text.substring(i, i+2).equals("ge"))

           )

             cntbitri++;

    }


   /* count trigramms */

   for ( int i= 0; i< text.length()-2; i++ ) {

     if (

          (text.substring(i, i+3).equals("ein"))

          ||(text.substring(i, i+3).equals("ich"))

          ||(text.substring(i, i+3).equals("nde"))

          ||(text.substring(i, i+3).equals("die"))

          ||(text.substring(i, i+3).equals("und"))

          ||(text.substring(i, i+3).equals("der"))

          ||(text.substring(i, i+3).equals("che"))

          ||(text.substring(i, i+3).equals("end"))

          ||(text.substring(i, i+3).equals("gen"))

          ||(text.substring(i, i+3).equals("sch"))

         ) cntbitri++;

   }

   return cntbitri;

  }


  /* count the number of nigramms and trigramms in an english text*/

  public static int englishText( String text ) {

    int cntbitri= 0; /*counter for bi- and trigramms */

   
   /* count bigramms */

   for ( int i= 0; i< text.length()-1; i++ ) {

     if (

          (text.substring(i, i+2).equals("th"))

          ||(text.substring(i, i+2).equals("he"))

          ||(text.substring(i, i+2).equals("an"))

          ||(text.substring(i, i+2).equals("in"))

          ||(text.substring(i, i+2).equals("er"))

          ||(text.substring(i, i+2).equals("re"))

          ||(text.substring(i, i+2).equals("on"))

          ||(text.substring(i, i+2).equals("es"))

          ||(text.substring(i, i+2).equals("ti"))

          ||(text.substring(i, i+2).equals("at"))

         )

       cntbitri++;

   }



   /* count trigramms */

   for (int i= 0; i< text.length()-2; i++) {

     if (

          (text.substring(i, i+3).equals("the"))

          ||(text.substring(i, i+3).equals("ing"))

          ||(text.substring(i, i+3).equals("and"))

          ||(text.substring(i, i+3).equals("ion"))

          ||(text.substring(i, i+3).equals("tio"))

          ||(text.substring(i, i+3).equals("ent"))

          ||(text.substring(i, i+3).equals("ere"))

          ||(text.substring(i, i+3).equals("her"))

          ||(text.substring(i, i+3).equals("ate"))

          ||(text.substring(i, i+3).equals("ver"))

     ) cntbitri++;

   }

   return cntbitri;

  }



  public static int findKeyCaesar(String origin) {
    /* proccedding:

     * search for most frequent char in encoded text and assume it is
     * one of the three most frequent letters in german or english
     * language.

     * decode text end test if it is decipheable
     */
   origin= takeOutPunctuation( origin );

     
   String text= "";
   /* number of occurence of most frequent char: */

   int mostFrequentChrValue= 0;

   int mostFrequentChr= 0;     //most frequent char in text


   char[] en= {'e','t','a',};  //most frequent letters in english

   char[] ge= {'e','n','i',};  //most frequent letters in german


   int biTriMax= 0;            //maximal value of bi- and trigramms

   int biTriTemp= 0;


   int displacement= 0;
   int key= 0;

   double kindex= determineKoinzidenzindex(origin);

     

/*

    System.out.print("Koinzidenzindex: "+ kindex );

    if ( kindex < 0.07 ) {

       System.out.println( " english text" );

    } else {

        System.out.println(" german text" );
    }

    System.out.println( );

*/

   /* define most frequent char */

   int[] chr= frequencyAnalysis(origin);



   for ( int i= 0; i< chr.length-1; i++) {

     if ( mostFrequentChrValue< chr[i] ) {

       mostFrequentChrValue= chr[i];

       mostFrequentChr= i;

     }

   }//for

   
   /*assume most frequent char as (e,t,a)(engl.) or (e,n,i)(germ.) */

   for ( int k= 0; k< en.length; k++ ) {
      /* decide if text german or english */

     if ( kindex < 0.07 ) {
       /*assumed char causes certain displacement */

       displacement= (mostFrequentChr+'a') -  (int) en[k]  ;   

     } else {

       displacement= (mostFrequentChr+'a') -  (int) ge[k]  ;

     }


     if ( kindex < 0.07) {

       text= decryptCaesar(origin, displacement);

       biTriTemp= englishText(text);

     } else {

       text= decryptCaesar(origin, displacement);

       biTriTemp= germanText(text);

     }


     /* displacement causing highest biTri value is key */

     if ( biTriMax< biTriTemp ) 

       {

         biTriMax= biTriTemp;

         key= displacement;

       }

   }


   System.out.println("Schluessel lautet: "+ key );

   return key;

  }


  public static String encryptCaesar( String text, int key ) {
    return modifyText(text, key);
  }

  public static String decryptCaesar( String text, int key ) {
    key*= -1;
    return modifyText(text, key);
  }


  public static String modifyText( String text, int key ) {
    String encrypted= "";
  
    key%= 26;

    for ( int i= 0; i< text.length(); i++ ) {

      int currentChar= (int) text.charAt(i);
      int code= currentChar;

      /*lower case letters*/
      code= filterSigns(currentChar, code, key, 97, 122);

      /* upper case letters */
      code= filterSigns(currentChar, code, key, 65, 90);

      /* numbers */      
      code= filterSigns(currentChar, code, key, 48, 57);

      encrypted+= (char) code; 
    }

    return encrypted;
  }

  /*replaces char only if it is situated in given boundarys*/
  public static int filterSigns(int currentChar, int code, int key,
                             int lowerBoundary, int upperBoundary ) {

    int range= upperBoundary - lowerBoundary + 1;

    if ( (currentChar >= lowerBoundary) & 
         (currentChar <= upperBoundary)   ) {

        code= currentChar + key;

        while ( code > upperBoundary ) {

          code-= range;

        }

        while( code < lowerBoundary ) {

          code+= range;

        }        
      }

    return code;
  } 

}