【问题标题】:special characters to standard binary format标准二进制格式的特殊字符
【发布时间】:2014-02-13 16:33:44
【问题描述】:

我准备了一种将输入字符串转换为二进制格式'0'和'1'的方法:

public static string StringToBinary(string data)
{
    StringBuilder sb = new StringBuilder();
    char[] chararr = data.ToCharArray();
    foreach (char c in data.ToCharArray())
    {
        string appendedStr = Convert.ToString(c, 2).PadLeft(8, '0');
        sb.Append(appendedStr);
    }
    return sb.ToString();
}

将每个字符处理为 8 位的组成部分

然后我写了一个从二进制文件中恢复字符串的方法

public static string BinaryToString(string data)
{
    List<Byte> byteList = new List<Byte>();

    for (int i = 0; i < data.Length; i += 8)
    {
        byteList.Add(Convert.ToByte(data.Substring(i, 8), 2));
    }

    return Encoding.ASCII.GetString(byteList.ToArray());
}

这也将每 8 位作为一个字符处理,并且工作正常。 但是在我使用 (ψ , ≤ ,我认为所有特殊字符) 之类的字符的地方,它不起作用并从 BinaryToString 方法返回异常,因为它从 StringToBinary 转换为 14 位(对于 ≤ ),我尝试完成它向左加 0 到 16 位,返回另一个字符串序列 有人有解决办法吗??

【问题讨论】:

  • 您需要了解 Unicode 编码。
  • XY problem...你真正想要完成什么?
  • .NET 字符串是 Unicode(16 位),而不是 8 位字节。 ASCII 绝对不能保证是系统使用的非 Unicode 格式,因为它由系统的区域设置控制。非程序员使用的非美国计算机肯定会使用每个国家/地区的代码页而不是 ASCII
  • @PanagiotisKanavos 这甚至有点复杂。单个 unicode 字符可以分布在 2 个字节以上。示例:"čč".Normalize(NormalizationForm.FormKD) 打印为 čč,但 ToCharArray 为您提供 cˇcˇ。两者都是相同的字符串,但具有不同的“内存”数据。这也使得比较 unicode 字符串有些棘手,因为它们不一定需要“字节相等”才能“字符相等”。

标签: c#


【解决方案1】:

您假设您可以安全地遍历一个字符数组并从每个字符中获取一个字节。这是一个错误的假设。

相反,您需要先以给定的编码将字符串编码为字节数组。例如:

Encoding.Unicode.GetBytes(data);

然后您可以安全地将这些字节中的每一个转换为二进制。

另一方面,对于您读取的每 8 位,您将它们重新组合为一个字节,当您再次拥有整个字节数组时,您只需调用

Encoding.Unicode.GetString(byteData);

你已经完成了。

但是...为什么要将字符保存为二进制字符串?您实际上想解决什么问题?如果您正在尝试压缩之类的东西,那么您使用的方法效率极低……如果您需要使用它来序列化数据,为什么不使用十六进制或 Base-64 编码?

【讨论】:

  • 没关系,但我想要一种方法来迭代输出位以从“1”更改为“0”,反之亦然,每次更改后我都在散列函数上使用了新位,我希望你能理解我的问题,谢谢
  • @MaRiO 这是一种相当迂回的方式。您有位运算符来进行位操作。例如,使用unchecked((byte)~data[i])(其中 data[i] 是字节之一)可以轻松地将所有输出位从 1 更改为 0,反之亦然。位操作在 CPU 中是硬编码的,我认为转换为位字符串不会比简单地使用位运算符更好(|^&amp;~&lt;&lt;&gt;&gt;)。
  • 是的,特殊字符的解决方案是 Encoding.Unicode。 Unicode 处理特殊字符。如果您使用 Encoding.UTF8,那么您将无法管理特殊字符。例如,“și”将以二进制表示为“19 02 69 00”。使用 Encoding.Unicode.GetString(Encoding.Unicode.GetBytes("și")) 将正确读取字符“ș”。