【问题标题】:Confused about Vigenère cipher implementation in Java对 Java 中的 Vigenère 密码实现感到困惑
【发布时间】:2015-04-28 12:37:18
【问题描述】:

请有人解释下面突出显示的代码行。我完全不明白这条线是如何工作的。

你可以用这个例子来帮助我:

输入:攻击 关键词:柠檬 资源:LXFOPV

我不明白那行如何帮助将A 编码为L 和其他字母... ACSII 参与?

static String encrypt(String text, final String key) {
    String res = "";
    text = text.toUpperCase();
    for (int i = 0, j = 0; i < text.length(); i++) {
        char c = text.charAt(i);
        if (c < 'A' || c > 'Z') continue;
 ////////////////////////////////////////////////////////////////////////////
//please someone explain this line
        res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A'); 
////////////////////////////////////////////////////////////////////////

        j = ++j % key.length();
    }
    return res;
}

【问题讨论】:

    标签: java encryption vigenere


    【解决方案1】:

    背景

    代码使用字母的 ASCII 值。字母 A-Z 是 ASCII 值 65-90。

    想法是将两个字母相加,但如果值超过 90(称为modular arithmetic),则回绕。所以 91 实际上应该是 65(即Z + 1 = A)。

    Java 提供了一个 % 运算符来进行模运算 (x % n)。然而,这被设计用于处理一系列数字 0→n-1。因此,如果我们从每个字母中减去 65,那么我们就在 0→25 的范围内工作。这允许我们使用模数运算符 (x % 26)。

    这就是代码的作用:

    c + key.charAt(j) - 2 * 'A'
    

    这部分将两个字母相加,但也从它们中减去 65。写成这样可能更容易理解:

    (c - 'A') + (key.charAt(j) - 'A')
    

    您会注意到,您可以使用- 'A' 作为- 65 的便捷方式。

    现在我们有一个从零开始的值,但可能大于 25。所以我们对它取模:

    (c + key.charAt(j) - 2 * 'A') % 26
    

    然后我们需要将 65 添加回该值,以使其回到 ASCII 的 A-Z 范围内:

    (c + key.charAt(j) - 2 * 'A') % 26 + 'A'
    

    剩下的唯一步骤是将其转换为char,因为默认情况下结果是int

    res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A'); 
    

    示例

    如果输入是ATTACK,关键字是LEMON,那么在某些时候我们将不得不考虑输入字母T(ASCII 84)和关键字母M(ASCII 77) .

    从每个中减去 65,我们有 T=19 和 M=12。加在一起,我们得到 31。

    31 % 26 = 5。所以我们然后计算5+65=70,这是F的ASCII值。

    【讨论】:

    • 很好的解释,但 Java 的 char 包含 Unicode/UTF-16 代码单元,而不是 ASCII 代码点。是的,对于有问题的字符,所有值都是相同的,但认为char 的范围是 0-127 或者任何 16 位值都是有效的 UTF-16 代码单元可能会导致错误。算术只能在 char 值的特定范围内工作。
    • @TomBlodget 是的,好点。它不会影响此代码,但如果 OP 不会误解 char 可以容纳的内容,它会很有帮助。