F# 中的代理项 unicode 字符存在问题

本文关键字:字符 存在 问题 unicode 代理 | 更新日期: 2023-09-27 18:30:48

我正在使用字符串,其中可能包含代理项 unicode 字符(非 BMP,每个字符 4 个字节)。

当我使用 "''Uxxxxxxv" 格式在 F# 中指定代理项字符时 - 对于某些字符,它给出的结果与 C# 的情况不同。例如:

C#:

string s = "'U0001D11E";
bool c = Char.IsSurrogate(s, 0);
Console.WriteLine(String.Format("Length: {0}, is surrogate: {1}", s.Length, c));

给予: Length: 2, is surrogate: True

F#:

let s = "'U0001D11E"
let c = Char.IsSurrogate(s, 0)
printf "Length: %d, is surrogate: %b" s.Length c

给予: Length: 2, is surrogate: false

注意:某些代理项字符在 F# 中有效("''U0010011"、"''U00100011"),但其中一些不起作用。

问:这是 F# 中的错误吗?如何使用 F# 处理字符串中允许的代理项 unicode 字符(F# 是否具有不同的格式,或者只有使用 Char.ConvertFromUtf32 0x1D11E 的方法)

更新:
s.ToCharArray()给出了 F# [| 0xD800; 0xDF41 |]; 适用于 C# { 0xD834, 0xDD1E }

F# 中的代理项 unicode 字符存在问题

这是 VS2010(和 SP1)附带的 F# 编译器中的一个已知错误;修复显示在 VS11 位中,因此,如果你有 VS11 Beta 并使用 F# 3.0 编译器,你将看到它的行为符合预期。

(如果此处的其他答案/评论在此期间没有为您提供合适的解决方法,请告诉我。

这显然意味着 F# 在分析某些字符串文本时出错。您提到的字符是非 BMP 的事实证明了这一点,在 UTF-16 中,它应该表示为一对代理项。代理项是范围 0xD800-0xDFFF 范围内的单词,而生成的字符串中的字符都不适合该范围。

但是代理的处理不会改变,因为框架(引擎盖下的内容)是相同的。所以你的问题已经有了答案 - 如果你需要在代码中使用带有非 BMP 字符的字符串文字,你应该只使用 Char.ConvertFromUtf32 而不是 ''UXXXXXXXX 表示法。其余所有处理将一如既往。

在我看来,这与不同形式的规范化有关。在 C# 和 F# 中,s.IsNormalized() 都返回 true但在 C# 中

s.ToCharArray() 给我们 {55348, 56606}//0xD834, 0xDD1E

和 F#

s.ToCharArray() 给我们 {65533, 57422}//0xFFFD, 0xE04E

您可能知道System.Char.IsSurrogate是通过以下方式实现的:

   public static bool IsSurrogate(char c)
   { 
        return (c >= HIGH_SURROGATE_START && c <= LOW_SURROGATE_END); 
   }

哪里

   HIGH_SURROGATE_START = 0x00d800; 
   LOW_SURROGATE_END    = 0x00dfff;

因此,在 C# 中,第一个字符 (55348) 小于 LOW_SURROGATE_END但在 F# 中第一个字符 (65533) 不小于LOW_SURROGATE_END。

我希望这有所帮助。