【问题标题】:Caesar Cipher Java Program can't shift more than 23Caesar Cipher Java 程序不能移动超过 23
【发布时间】:2017-08-16 13:07:49
【问题描述】:

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

在我达到 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");
    }
}

【问题讨论】:

  • 你调试过你的代码吗?
  • ...plaintext += shift; } else { plaintext += shift; } — 这没有意义。您可以将plaintext += shift 语句放在else 之外。
  • 只是让您知道 - 过去的 'Z''z' 是少数与字母无关的字符。你会想跳过那些。
  • @Isaiah 如果用户回答了您的问题,请同时接受他的回答 (Accepting Answers: How does it work?)。如果不是,请说明什么仍未得到答复,这是 StackOverflow 的一个非常重要的部分,非常感谢。

标签: java caesar-cipher


【解决方案1】:

您的方法转变如何发挥作用?好吧,它利用了 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,以及为什么133 没有任何意义。

这里的关键字是UTF-16。 Java 中的字符以UTF-16 编码,并且有一些表格列出了该编码的所有字符及其特定的十进制数字,例如here

以下是相关摘录:

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


一些变化后您会遇到奇怪结果的原因是字母表只有 26 个符号

我想你会期望它重新开始,a 移动了 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 之后不会再次出现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 

因此,我们只移动相关部分22,而不是移动100。想象一下,因为100 / 26 ~ 3.85,角色在整个字母表中进行了三轮。在这三轮之后,我们进行剩余的0.85 轮,即22 步骤,将100 除以26 之后的剩余。这正是% 运算符为我们所做的。

经过22 步骤后,我们仍然可以超出界限,但最多可以超出一轮。我们通过减去字母大小来纠正这个问题。因此,我们不是走22 步,而是走22 - 26 = -4 步,它模拟“走 4 步到字母表末尾,然后再次从 'a' 开始,最后走 18 步到 's'”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 2017-03-25
    相关资源
    最近更新 更多