【问题标题】:Caesar Cipher with Ascii Characters带有 Ascii 字符的凯撒密码
【发布时间】:2017-12-07 00:38:47
【问题描述】:

我正在尝试使用带有关键位置整数的 ascii 字符来加密字符串。我有两种方法,一种用于加密,一种用于解密。

问题是当字符值高于 126 时,我尝试将其修改为 126,然后将 32 添加回其中,但我得到的数字远远超出了这些限制。

public static String encrypt(String s, int k) {
    char[] arr = s.toCharArray();
    int ascii;
    for(int i = 0; i < arr.length; i++) {
        ascii = (int) arr[i];
        ascii = ascii + k;
        // System.out.println(ascii);
        if (ascii > 126) {
            ascii = 32 + (126 % ascii);
            // System.out.print("Changed: " + ascii);
        }

        arr[i] = (char) ascii;
    }
    return String.valueOf(arr);
}

注释掉的两条线用于测试,更改后的值非常高,就像不是从 127 % 126 = 1 + 32 总共 33(预期值),我得到 15870。

【问题讨论】:

  • 考虑提供样本输入和预期/当前输出
  • 目前有超过 100 个 Caesar Cipher 问题的答案,并且大多数都包含相同的问题,不理解 ASCII 编码和/或模数 (%) 运算符。阅读它们,研究它们,调试你的代码,你可以使用调试器或使用 print 语句去洞穴人。

标签: java ascii


【解决方案1】:

首先,正如 mypetlion 所提到的,模运算 a % b 等于 a 除以 b 的余数。例如。 11 % 4 = 3, 8 % 15 = 8。准确地说,是值 k 满足 b * n + k = a, b * (n + 1) > a, k

至于为什么模数应该是 128 而不是 126,7 位 ascii 码从 0 到 127,总共 128 个值。另外我对 +32 的用途有点困惑,因为你已经 +k 了。

您也可以完全省略 if 块,因为对于范围 [0, 128) 中的任何 c,c % 128 = c。

所以我会写如下代码:

public static String encrypt(String s, int k) {
    char[] arr = s.toCharArray();
    for(int i = 0; i < arr.length; i++){
        arr[i] = (char) ((arr[i] + k) % 128);
    }
    return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
    char[] arr = s.toCharArray();
    for(int i = 0; i < arr.length; i++){
        arr[i] = (char) ((arr[i] + 128 - k % 128) % 128);
        // + 128 - k % 128 because I don't want do deal with negative numbers.
    }
    return String.valueOf(arr);
}

我相信我的代码可以正常工作(对于所有正的 k 值),但我无法解释为什么你的代码会产生一些疯狂的高 ascii 值。当我在我的 IDE 上运行你的代码时,它没有这样做,我也无法从你的代码中看到它为什么会这样。

最后,这种密码方法可以加密和解密,但请注意,ascii 确实包含许多不适合打印的控制字符。因此,如果您想将密码词汇限制为仅限字母和标点符号,则需要进行一些字符映射来限制要加密和加密的字符。这将要复杂得多,更不用说您必须考虑诸如 Windows 中的 CR+LF 和 Unix 中的 LF 之类的问题。下面是一个简单的例子,只对字母进行加解密。

public static int asciiToCustom(char ascii) {
// Maps 65-90 & 97-122 to 0-51.
    int customCode;
    if(ascii >= 65 && ascii <= 90){
        customCode = ascii - 65;
    }
    else if(ascii >= 97 && ascii <= 122){
        customCode = ascii - 71;
    }
    else{
        throw new RuntimeException("not a letter!");
    }
    return customCode;
}
public static char customToAscii(int custom) {
// Maps 0-51 to 65-90 & 97-122.
    int ascii;
    if(custom >= 0 && custom <= 25){
        ascii = custom + 65;
    }
    else if(custom >= 26 && custom <= 51){
        ascii = custom + 71;
    }
    else{
        throw new RuntimeException("not a valid custom code!");
    }
    return (char) ascii;
}
public static String encrypt(String s, int k) {
    char[] arr = s.toCharArray();
    for(int i = 0; i < arr.length; i++){
        if(Character.isLetter(arr[i])){
            arr[i] = customToAscii((asciiToCustom(arr[i]) + k) % 52);
        }
    }
    return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
    char[] arr = s.toCharArray();
    for(int i = 0; i < arr.length; i++){
        if(Character.isLetter(arr[i])){
            arr[i] = customToAscii((asciiToCustom(arr[i]) + 52 - k % 52) % 52);
            // + 52 - k % 52 because I don't want do deal with negative numbers.
        }
    }
    return String.valueOf(arr);
}

【讨论】:

    【解决方案2】:

    您的模语句一开始是倒着写的。试试:

    ascii = 32 + (ascii % 126);
    

    【讨论】:

    • 改变了!两种方法我都试过了,一个给我15870,另一个给我3370
    • 您的第二个打印语句是print 而不是println。您确定 70 不只是数组中的下一个值吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    相关资源
    最近更新 更多