Caesar Cipher Java程序不能超过23个

时间:2017-02-13 17:25:55

标签: java caesar-cipher

我正在创建一个程序来执行 Caesar Cipher ,当我按下Enter键时会将单词中的字母移动一次,并提示用户再次切换或退出。

直到我 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 :(得分: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

好的,现在我们知道如何将char解释为int,让我们分析为什么65代表字符A以及为什么133UTF-16没什么意义。

此处的关键字为 UTF-16 。 Java中的字符以65编码,并且有表格列出了该编码的所有字符及其特定的十进制数,如here

以下是相关摘录:

UTF-16 table showing characters around 'A'

这解答了为什么A代表133以及为什么a没有任何意义。

您在某些转变之后遇到奇怪结果的原因是字母表的大小只有 26个符号

我认为你会希望它重新开始,26移动a再次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

将其与表格中的相关部分进行比较:

UTF-16 table showing characters around '{'

所以在a再次来{之后,而不是%

所以在神秘问题解决之后,让我们现在讨论如何修复它并让你的代码变得更聪明。

您可以简单地检查边界,例如&#34; ,如果它大于&#39; z&#39;的值。或者小于&#39;然后再将其恢复到正确的范围&#34;。我们可以使用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而不是100 / 26 ~ 3.85。想象一下,角色在整个字母表中三轮因为0.85。在那些三轮之后,我们将22分为100轮,余数,将26除以{{1} }}。这正是%运营商为我们所做的事情。

在执行22步之后,我们仍然可以超过界限,但最多可以超过一轮。我们通过减去字母大小来纠正这个问题。因此,我们不是采取22步骤,而是采用22 - 26 = -4步骤模拟&#34; 将4个步骤移至字母表的末尾,然后从&#39; a&#39;开始。再次,最后走了18步到#&#39; &#34;。