F#中的代理unicode字符问题

时间:2012-04-12 12:58:49

标签: c# unicode f# surrogate-pairs

我正在处理字符串,它可能包含代理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 }

3 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:1)

在我看来,这与不同形式的规范化有关。 在C#和F#中都有.snNormalized()返回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。

我希望这会有所帮助。