加密包含unicode的字符串会导致无法识别的字符

Adi*_*Aji 2 c# encryption caesar-cipher

我正在尝试在C#中加密字符串:

static public string Encrypt(char[] a)
{
    for (int i = 0; i < a.Length; i++)
    {
        a[i] -= (char)(i + 1);
        if (a[i] < '!')
        {
            a[i] += (char)(i + 20);
        }
    }
    return new string(a);
}
Run Code Online (Sandbox Code Playgroud)

现在,当我输入这个字符串时:

"Qui habite dans un ananas sous la mer?".
Run Code Online (Sandbox Code Playgroud)

加密结果如下:

`Psf3c[[ak[3XT`d3d\3MYKWIZ3XSXU3L@?JAMR`
Run Code Online (Sandbox Code Playgroud)

在@之后,那里有一个无法辨认的角色.我不知道它是怎么到达的,我不知道为什么.

如果我尝试解密它(使用这种方法:)

static public string Decrypt(char[] a)
{
    for (int i = 0; i < a.Length; i++)
    {
        a[i] += (char)(i + 1);
        if ((a[i] - 20) - i <= '!')
        {
           a[i] -= (char)(i + 20);
        }
    }
    return new string(a);
}
Run Code Online (Sandbox Code Playgroud)

这是(不正确的)输出:

Qui habite dans un ananas sous laamerx.

如何允许加密例程访问unicode字符?

Eri*_*rik 5

你获得一个不可打印的角色的原因是这一行:

a[i] -= (char)(i + 1);
Run Code Online (Sandbox Code Playgroud)

发生的事情是你的内部空间la mer是字符串的第34个位置,空格的等效整数值是0x20 = 32.这意味着当你减去(i+1)你得到-2时.但是你将结果存储在a中char,这是一个无符号类型,所以这实际上变成0xFFFE = 65534.然后当你测试时a[i] < '!'你得到假,因为a[i]现在是一个大的正数.

相反,你应该做什么(如果你真的想要实现这个算法)是将结果存储在有符号的类型中,并在你做的时候操纵它,然后在最后将它转换为char.

    int value = (int)a[i] - (i + 1);
    if (value < (int)'!')
    {
        value += i + 20;
    }
    a[i] = (char)value;
Run Code Online (Sandbox Code Playgroud)

(强调额外的类型演员.)

它可能没有必要,但我建议在Decrypt方法中使用相同的模式.通常更容易推理出适用于临时变量的代码,而不是编辑适当的东西.