2017-02-13 5 views
1

シーザー暗号を実行するプログラムを作成しています。これは、入力した単語を一度シフトして、終了する。Caesar Cipher Javaプログラムは23を超えてシフトできません

23シフトになるまで動作していますが、何らかの理由で文字以外の記号が使用され始めましたが、なぜこのようなことが起こっているのかわかりません。

提案がありますか?コードは次のとおりです。

import java.io.File; 
import java.io.IOException; 
import java.util.Scanner; 

public class Cipher { 

    public static void main(String[] args) { 

     // encrypted text 
     String ciphertext; 

     // input from keyboard 
     Scanner keyboard = new Scanner(System.in); 

     if (args.length > 0) { 
      ciphertext = ""; 
      try { 
       Scanner inputFile = new Scanner(new File(args[0])); 
       while (inputFile.hasNext()) 
        ciphertext += inputFile.nextLine(); 
      } catch (IOException ioe) { 
       System.out.println("File not found: " + args[0]); 
       System.exit(-1); 
      } 
     } else { 
      System.out.print("Please enter text--> "); 
      ciphertext = keyboard.nextLine(); 
     } 

     // ----------------------------------------------------------------- 

     int distance = 0; // how far the ciphertext should be shifted 
     String next = ""; // user input after viewing 
     while (!next.equals("quit")) { 
      String plaintext = ""; 
      distance += 1; 
      for (int i = 0; i < ciphertext.length(); i++) { 
       char shift = ciphertext.charAt(i); 
       if (Character.isLetter(shift)) { 
        shift = (char) (ciphertext.charAt(i) - distance); 
        if (Character.isUpperCase(ciphertext.charAt(i))) { 
         if (shift > '0' && shift < 'A') { 
          shift = (char) (shift + 26); 
          plaintext += shift; 
         } else { 
          plaintext += shift; 
         } 
        } 
        if (Character.isLowerCase(ciphertext.charAt(i))) { 
         if (shift > '0' && shift < 'a' && ciphertext.charAt(i) < 't') { 
          shift = (char) (shift + 26); 
          plaintext += shift; 
         } else { 
          plaintext += shift; 
         } 
        } 
       } else { 
        plaintext += shift; 
       } 
      } 

      System.out.println(ciphertext); 

      // At this point, plaintext is the shifted ciphertext. 
      System.out.println("distance " + distance); 
      System.out.println(plaintext); 
      System.out.println("Press enter to see the next option," 
        + "type 'quit' to quit."); 
      next = keyboard.nextLine().trim(); 
     } 
     System.out.println("Final shift distance was " + distance + " places"); 
    } 
} 
+1

コードをデバッグしましたか? –

+0

'...平文+ =シフト; } else {プレーンテキスト+ =シフト; } ' - これは意味をなさない。 'else'の外側に' plaintext + = shift'ステートメントを置くことができます。 –

+1

過去の '' Z'''と '' z'''は手紙とは何の関係もない文字です。あなたはそれらをスキップしたいと思うでしょう。 – Makoto

答えて

0

方法の変更はどのように機能しますか?さて、charは、Javaではintという単純な数字でも表示されるという事実を利用しています。

はそのため、あなたはこのようなものを行うことができます。でも、その

char c = 'A';         // Would print: A 
int cAsValue = (int) c;      // Would print: 65 
int nextValue = cAsValue + 1;     // Would print: 66 
char nextValueAsCharacter = (char) nextValue; // Would print: B 

かを:

int first = (int) 'A';    // Would print: 65 
int second = (int) 'D';    // Would print: 68 
int third = first + second;   // Would print: 133 
char thirdAsCharacter = (char) third; // Would not print anything meaningful 

さて、今私たちがintとしてcharを解釈できる方法を知っていることを、聞かせてなぜ65が文字Aを表し、なぜ133が意味がないのかを分析します。

ここにキーワードはUTF-16です。 Javaの文字はUTF-16にエンコードされており、そのエンコードのすべての文字を特定の10進数で表示するテーブルがあります(hereなど)。ここで

は、関連の抜粋です:

UTF-16 table showing characters around 'A'

65A、なぜ133が意味のあるものではありませんを表し、なぜこれが答えます。


あなたはいくつかのシフト後に奇妙な結果を経験する理由はアルファベットのみ26シンボルの大きさを持っていることです。

もう一度やり直してa26に変更してからもう一度aになると思います。残念ながら、あなたのコードが十分にスマートではありません。しかし、それは単に現在の文字を取り、そのようなことへのシフトを追加します:

UTF-16 table showing characters around '{'

char current = 'a'; 
int shift = 26; 

int currentAsInt = (int) current;  // Would print: 97 
int shifted = currentAsInt + shift;  // Would print: 123 
char currentAfterShift = (char) shifted; // Would print: { 

は、テーブル内の該当部分にあることを比較します

だからzの後にもう一度aが来るのではなく、{になります。


謎が解消したら、修正してコードをスマートにする方法を話しましょう。

境界が「z」の値より大きい場合や「a」より小さい場合は「」のように境界を確認してから、正しい範囲に再度戻すことができます "。 モジュロ演算子%で指定すると簡単に実行できます。数値を別のものに分割し、除算の残りの部分を返します。ここで

は、我々はそれを使用する方法である。

char current = 'w'; 
int shift = 100; 
int alphabetSize = 26; // Or alternatively ('z' - 'a') 

int currentAsInt = (int) current;   // Would print: 119 
int shiftInRange = shift % alphabetSize; // Would print: 22 
int shifted = currentAsInt + shiftInRange; // Would print: 141 (nothing meaningful) 

// If exceeding the range then begin at 'a' again 
int shiftCorrected = shifted; 
if (shifted > 'z') { 
    shiftCorrected -= alphabetSize; // Would print: 115 
} 

char currentAfterShift = (char) shiftCorrected; // Would print: s 

ので、代わりの100によってシフト我々は関連部分のみ、22ことがずれます。文字がの3つのラウンドのアルファベット全体で100/26 ~ 3.85になると想像してください。我々は22手順、26によって100を分割した後余りである残りの0.85ラウンドを行くそれら3回行った後。それはまさに%のオペレータが私たちのためにしたものです。

22ステップを行った後も、制限を超えて最大限に1ラウンドを超えることができます。アルファベットサイズを減算することでそれを修正します。だから22のステップに行くのではなく、 ""をアルファベットの最後に移動してから、もう一度 'a'から始めて、最後に18ステップを ''にエミュレートするステップが22 - 26 = -4になります。

関連する問題