凯撒密码在 Java 中解码错误

Caesar Cipher decoded wrongly in Java

我已经在 Java 8 中实现了凯撒密码算法。

问题

Heute ist Freitag.

使用 22 作为密钥生成此编码文本:

^{

{6

6{

w}D

再次解码得到这个输出:

Heu

e is

Frei

ag.

代码和描述

应该注意的是,我的算法不关心像'\n'这样的字符,这意味着一些字符可能会被翻译成转义序列或空格等。 这也完全是我想要发生的事情,认为它不起作用。

    public String encode(String txt, int key) {
    if(key <= 0)
        return txt;

    String result = "";
    for (int i = 0; i < txt.length(); i++) {
        int x = (txt.charAt(i) + key) % 128;
        result += (char) x;
    }
    System.out.println(result);
    return result;
    }
    public String decipherM(String txt, int key) {
    if(key <= 0)
        return txt;

    String result = "";
    for (int i = 0; i < txt.length(); i++) {
        int x = (txt.charAt(i) - key) % 128;
        if(x < 0)
            x += 128;

        result += (char) x;
    }
    System.out.println(result);
    return result;
}

问题

我真的很想知道为什么它不适用于转义序列或其他非字母字符。

控制字符具有定义的含义,文本处理工具可能会保留其含义甚至删除那些没有有效含义的控制字符,而不是保留准确的字节表示形式。

请注意,当您超越 ASCII 时,这甚至可能发生在普通字符上,例如由于您使用了德语示例文本,因此您必须知道两个 Unicode 代码点序列 \u00E4\u0061\u0308 在语义上是等价的,它们都指的是字符 ä 并且您不能依赖保留两种形式的文本处理工具。

毕竟,为了通过文本处理工具无损传输字节序列,发明了像 Base 64 这样的编码是有原因的。

对于像您这样简单的编码,最好简单地禁止源字符串中的控制字符并仅在 ASCII 非控制字符范围内循环:

public String encodeRotation(String txt, int distance) {
    int first = ' ', last = 128, range = last - first;
    while(distance<0) distance+=range;
    if(distance == 0) return txt;
    char[] buffer = txt.toCharArray();
    for (int i = 0; i < txt.length(); i++) {
        char c = buffer[i];
        if(c<first || c>=last)
            throw new IllegalArgumentException("unsupported character "+c);
        buffer[i] = (char) ((c - first + distance) % range + first);
    }
    return String.valueOf(buffer);
}

public String decodeRotation(String txt, int key) {
    return encodeRotation(txt, -key);
}
System.out.println(encodeRotation("Heute ist Freitag.", 22));
^{+*{6)*6\({*w}D
System.out.println(decodeRotation("^{+*{6)*6\({*w}D", 22));
Heute ist Freitag.