【问题标题】:Can I mix UTF-16 conversion with UTF-8 conversion between bytes and string?我可以在字节和字符串之间混合使用 UTF-16 转换和 UTF-8 转换吗?
【发布时间】:2014-03-20 15:22:38
【问题描述】:

短版

这是一个恒等函数吗?

f = (gₐ · hᵤ · gᵤ · hₐ)

地点:

  • hₐ 是从字节到字符串的UTF-16 conversion
  • gₐ是从字符串到字节的UTF-16转换,
  • gᵤEncoding.UTF8.GetBytes()
  • hᵤEncoding.UTF8.GetString()

加长版

我正在使用 WebSocket4Net 在 C# 应用程序和 C# 服务之间通过 WebSockets 发送和接收消息。

有些消息是二进制的,我应该在与库交互时将它们从字符串转换为字符串,因为虽然它的Send() 方法可以发送字节数组,但它的MessageReceived 仅将接收到的消息作为字符串进行通信。

为了将字节转换为字符串并将字符串转换为字节,我遵循the answer by Mehrdad,其中使用了 .NET Framework 的内部编码,即 UTF-16。

另一方面,根据代码源(例如参见DraftHybi10Processor.cs, line 114),WebSocket4Net 使用 UTF-8 将字符串转换为字节,将字节转换为字符串。

它会引起问题吗?是否可能丢失数据?

【问题讨论】:

  • 字符串到字节的转换(反之亦然)如何编码不可知?
  • Mehrdad 的回答非常有缺陷。他仍在使用编码,他只是在没有意识到的情况下使用 UTF-16 编码(并且由于字节顺序问题而扼杀了可移植性)。我看不出这比使用显式编码更好。此外,使用 UTF-8 编码 unicode-to-bytes 数组会浪费大量空间:)
  • @Luaan 已经死了......如果没有编码,您无法从字符串转换为字节。这是不可能的。
  • @MainMa:这个答案是一种非常危险的方式来做一件事。作为危险的证明,你根本不明白他在那里做什么。正如 Luaan 所说,“与编码无关的转换”没有意义。这不是转换,而是重新解释
  • @jalf 未明确使用字符串中的编码仍在使用编码。当你在别处使用这些字节时,你完全被搞砸了,不知道为什么。

标签: c# encoding utf-8


【解决方案1】:

如果您需要将二进制数据作为字符串发送,那么这就是 Base-64 和类似编码的用途。如果您需要将字符串作为字符串发送......好吧,将其作为字符串发送。如果您需要将字符串作为字节发送,Unicode (UTF-16) 或 UTF-8 就可以了。字符串不是简单的字节数组(即使它们可以在必要时以这种方式表示)。尤其是 Unicode 是一种相当复杂的编码(参见http://www.joelonsoftware.com/articles/Unicode.html;阅读它——这是必须的)。您知道您可以获得将单个字符分成 5 个字节的 unicode 规范化吗?相同的字符也可以解释为 2。或者完全不同的数字。我没有观察到它,但我希望某些字节数组在 UTF-16(这是 .NET 中当前的默认字符串编码)中完全无效。

我不会去证明你的“双重编码”是有缺陷的。我不确定,它甚至可能会起作用。但是,您将要获得的字符串将非常愚蠢,并且您将很难对其进行编码以确保您没有发送命令或其他内容。

更重要的是 - 你没有表现出意图。您正在进行微优化,并牺牲了可读性。更糟糕的是,您依赖于实现细节,这些细节对于更高版本的 .NET 而言不一定是可移植的或稳定的,更不用说其他环境了。

除非您有非常非常好的理由(基于实际性能分析,而不是“直觉”),否则请选择简单易读的解决方案。如果需要,您可以随时改进。

编辑:示例代码说明为什么使用 Unicode 编码非 Unicode 字节是一个坏主意:

Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(new byte[] { 200, 8 }))

输入的两个字节变成了四个字节,{ 239, 191, 189, 8 }。不是你想要的。

【讨论】:

  • Base-64 确实是一种通用的方法,但在我的情况下不是。就我而言,WebSockets 通信通常是通过低速网络连接完成的,4:3 的比例会很烦人。
  • 是的,有些字节数组是非法的 UTF-8 或 UTF-16。
  • 好吧,直到 web 套接字允许直接发送二进制数据(这是一个正在实现的功能 - WebSocket4Net 已经支持它),这是唯一可靠和简单的方法。如果您真的想发送字符,请忽略 UTF-8 和 UTF-16 - 它们很复杂。相反,用一些 ASCII 编码对其进行编码——这些不是语言,只是原始的字符字节表。该转换保证为 1:1(每个字符都是唯一的并且具有单字节表示)。最好的实际上是 7 位 ASCII(即未扩展),如果您处理“悬空”位 - 保证完美的 UTF-8。
  • @MainMa 需要注意的重要一点是,可以表示为较短“字节数组”的 UTF-8 字符应该是。因此,如果您有一个 2 字节的 UTF-8“字符”,则可以将其转换为 1 字节的 UTF-8 - 您的 2 个输入字节现在被转换为 1。字符串没有问题(字符串仍然是相同),但它不再是相同的字节数组。
  • @Luaan 我们大量使用它,但仅用于浏览器客户端,并且仅连接到我们自己编写的 Websocket 服务器。就浏览器而言,几乎所有浏览器都直接从“默认情况下未实现或禁用 Websockets”到“websockets 在二进制和 UTF-8 模式下工作正常”。我认为 Safari 5.1 可能是个问题,但没有比这更近或更广泛使用的了。 (但我不能说非浏览器的实现)
猜你喜欢
  • 2023-03-24
  • 2020-01-28
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
相关资源
最近更新 更多