c# - Convert.FromBase64String 有时返回 unicode,或 UTF-8

标签 c# unicode encoding utf-8 base64

有时字节数组b64是UTF-8,有时是UTF-16。我一直在网上阅读 C# 字符串始终是 UTF-16,但我这里不是这种情况。为什么会发生这种情况,我该如何解决?我有一个将 base64 字符串转换为普通字符串的简单方法:

public static string FromBase64(this string input)
{
    String corrected = new string(input.ToCharArray());
    byte[] b64 = Convert.FromBase64String(corrected);
    if (b64[1] == 0)
    {
        return System.Text.Encoding.Unicode.GetString(b64);
    }
    else
    {
        return System.Text.Encoding.UTF8.GetString(b64);
    }

}

同样的事情发生在我的 base 64 编码器上:

public static string ToBase64(this string input)
{
    String b64 = Convert.ToBase64String(input.GetBytes());
    return b64;
}

public static byte[] GetBytes(this string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

例子: 在我的电脑上,“cABhAHMAcwB3AG8AcgBkADEA”解码为:

'p','\0','a','\0','s','\0','s','\0','w','\0','o','\0','r','\0','d','\0','1','\0'

但是在我同事的电脑上是:

'p','a','s','s','w','o','r','d','1'

编辑:

我知道我创建的字符串来自文本框,并且我保存它的文件始终是 UTF-8,所以所有内容都指向导致我的编码切换的 Convert 方法。

更新:

进一步深入研究后,我的同事似乎在他的代码版本中注释了一行非常重要的代码,即将从文件读取的值保存到哈希表中的那一行。我使用的默认值是 UTF-8 base64 值,因此我要将默认值更正为 utf-16 值,然后我可以清理代码,删除任何 UTF8 引用。

此外,我一直天真地使用从网站检索到的 UTF-8 base64 编码,却没有意识到自己陷入了什么境地。有趣的是,如果我的同事没有评论保存文件值的行,我永远不会发现这个事实。

代码的最终版本:

public static string FromBase64(this string input)
{
    byte[] b64 = Convert.FromBase64String(input);
    return System.Text.Encoding.Unicode.GetString(b64);
}

public static string ToBase64(this string input)
{
    String b64 = Convert.ToBase64String(input.GetBytes());
    return b64;
}

public static byte[] GetBytes(this string str)
{
    return System.Text.Encoding.Unicode.GetBytes(str);
}

最佳答案

首先我要揭穿题名:

Convert.FromBase64String() returns Unicode sometimes, or UTF-8

事实并非如此。然后提供相同的输入,有效的 base64 编码文本,Convert.FromBase64String() 总是返回相同的输出。

继续前进,您无法仅通过检查有效负载来明确确定用于字符串的编码。你试图用

if (b64[1] == 0)
    // encoding must be UTF-16

事实并非如此。绝大多数 UTF-16 字符元素都无法通过该测试。无论您如何尝试编写此测试都注定要失败。这是因为当解释为不同的编码时,存在定义明确的字符串的字节数组。换句话说,例如,可以构造在被视为 UTF-8 或 UTF-16 时有效的字节数组。

因此,您必须先验地知道有效负载是编码为 UTF-16、UTF-8 还是其他编码。

解决方案是在 base64 编码之前跟踪原始编码。将该信息与 base64 编码的有效负载一起传递。然后在解码时,您可以确定使用哪种 Encoding 解码回字符串。

在我看来,您的字符串全部来自 UTF-16 .net 字符串。在这种情况下,您永远不会有 UTF-8 字符串,并且应该始终使用 UTF-16 进行解码。那就是你使用 Encoding.Unicode.GetString()

此外,您代码中的 GetBytes 方法很差。应该是:

public static byte[] GetBytes(this string str)
{
    return Encoding.Unicode.GetBytes(str);
}

另一个奇怪的地方:

String corrected = new string(input.ToCharArray());

这是一个空操作。

最后,当编码为 UTF-8 时,您的文本很可能会更紧凑。因此,也许您应该考虑在应用 base64 编码之前这样做。


关于您的更新,您所说的不正确。这段代码:

string str = Encoding.Unicode.GetString(
    Convert.FromBase64String("cABhAHMAcwB3AG8AcgBkADEA"));

password1 分配给 str,无论它在哪里运行。

关于c# - Convert.FromBase64String 有时返回 unicode,或 UTF-8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21269900/

相关文章:

c# - 为什么要使用 Parse 将字符串转为 int?

.net - 在 .NET 中将非 ascii(unicode)数字字符串解析为整数

java - parseJSON 将在有效 JSON 上抛出错误

mysql - 无法使用 ADO/ODBC 将重音字符写入 MySQL

python - 从句子字符串中剥离所有表情符号

c# - 如何防止阿拉伯字符被AntiXssEncoder重新编码?

c# - 运行 Web 作业在启动时出现 ArgumentNullException

C# LINQ 一遍又一遍地执行相同的工作

c# - 根据用户未输入的数据验证模型

c++ - 以字节模式将宽字符串写入文件停止