Javakurs/Übungsaufgaben/Cäsar-Chiffre/Musterlösung
< Javakurs | Übungsaufgaben | Cäsar-Chiffre
/* 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; } }