我正在处理字符串,它可能包含代理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 }
答案 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。
我希望这会有所帮助。