【问题标题】:Defining 4-byte UTF-16 character in a string在字符串中定义 4 字节 UTF-16 字符
【发布时间】:2014-01-19 09:33:11
【问题描述】:

我已阅读 a question about UTF-8, UTF-16 and UCS-2,几乎所有答案都表明 UCS-2 已过时,C# 使用 UTF-16。

但是,我在 C# 中创建 4 字节字符 U+1D11E 的所有尝试都失败了,所以我实际上认为 C# 仅使用 UTF-16 的 UCS-2 子集。

有我的尝试:

string s = "\u1D11E"; // gives the 2 character string "ᴑE", because \u1D11 is ᴑ
string s = (char) 0x1D11E; // won't compile because of an overflow
string s = Encoding.Unicode.GetString(new byte[] {0xD8, 0x34, 0xDD, 0x1E}); // gives 㓘ờ

C# 字符串真的是 UTF-16 还是真的是 UCS-2?如果它们是 UTF-16,我如何将小提琴谱号放入我的 C# 字符串中?

【问题讨论】:

  • 最简单的就是在源代码中包含字符,即string s = "????";。我建议您使用 UTF-8 编码保存您的 .cs 文件。 Supplementary Multilingual Plane 中的这个字符将占用 UTF-8 中的四个八位字节。当保存在内存中时,它将占用两个 UTF-16 代码单元或 char 值,即所谓的代理对。
  • 是的,我在 Wikipedia 上读到过,这就是我尝试 Encoding.GetString() 方法的原因。

标签: c# unicode encoding character-encoding utf-16


【解决方案1】:

根据 C# 规范,长度超过 4 个十六进制字符的字符使用\U(大写 U)和 8 个十六进制字符进行编码。一旦在字符串中正确编码,就可以使用任何 unicode 编码正确导出;

string s = "\U0001D11E";

foreach (var b in Encoding.UTF32.GetBytes(s))
    Console.WriteLine(b.ToString("x2"));

Console.WriteLine();

foreach (var b in Encoding.Unicode.GetBytes(s))
    Console.WriteLine(b.ToString("x2"));

> 1e
> d1
> 01
> 00
>
> 34
> d8
> 1e
> dd

【讨论】:

  • 您的示例使用 UTF-32 来获取字节。我要求使用 UTF-16。
  • @ThomasW。我只是使用 UTF32 清楚地表明 4 字节字符已使用 \U 正确编码到字符串中。 UTF-16,每个字符少于 4 个字节的多字节编码使得字节的十六进制转储与原始值之间的联系不太清楚。
  • @ThomasW。添加了一个 UTF-16 示例。
【解决方案2】:

C# 肯定使用 UTF-16。定义 U+0000 - U+FFFF 范围以上字符的正确方法是使用escape sequence,它允许使用 8 个十六进制数字定义字符:

string s = "\U0001D11E";

如果您使用\u1D11E,它会被解释为U+1D11 字符后跟E

使用这些字符时要记住的一点是,String.Length property 和大多数字符串方法适用于 UTF-16 代码单元,而不是 Unicode 字符。来自 MSDN 文档:

Length 属性返回此实例中 Char 对象的数量,而不是 Unicode 字符的数量。原因是一个 Unicode 字符可能由多个 Char 表示。使用 System.Globalization.StringInfo 类来处理每个 Unicode 字符而不是每个 Char。

【讨论】:

  • +1 因为我不知道 StringInfo。但是,上面的两个变体也在屏幕上显示为 2 个字符。
  • 你用什么在屏幕上显示字符串?
  • 我尝试了带有标签和文本框的 WinForms,默认字体(可能是 Arial)
  • 应该可以。不过,我发现了另一个问题;查看更新。
【解决方案3】:

改用大写U:

  string s = "\U0001D11E";

你忽略了大多数机器都是小端的:

  string t = Encoding.Unicode.GetString(new byte[] { 0x34, 0xD8, 0x1E, 0xDD });

【讨论】:

  • 我非常喜欢你在逐字节编码中发现了我的错误。尽管其他答案也找到了大写U的解决方案,但这就是我接受您的答案的原因。
  • 但是除非您的.cs 源文件保存在某个 1 字节的“ANSI”代码页中,否则您应该考虑简单地执行string s = "?";。这很自然。
猜你喜欢
  • 2014-01-19
  • 2016-09-07
  • 2018-12-16
  • 2020-07-17
  • 1970-01-01
  • 1970-01-01
  • 2018-02-18
  • 2011-08-09
相关资源
最近更新 更多