10

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

当我使用“ \Uxxxxxxxxv ”格式在 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 }

4

3 回答 3

8

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

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

于 2012-04-12T22:35:29.213 回答
5

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

但是代理的处理并没有改变,因为框架(引擎盖下的东西)是一样的。因此,您的问题已经有了答案 - 如果您的代码中需要带有非 BMP 字符的字符串文字,您应该只使用Char.ConvertFromUtf32而不是 \UXXXXXXXX 表示法。所有其余的处理都将与往常一样。

于 2012-04-12T13:34:20.010 回答
1

在我看来,这与不同形式的规范化有关。在 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。

我希望这有帮助。

于 2012-04-12T13:23:01.897 回答