【问题标题】:Issue with surrogate unicode characters in F#F# 中的代理 unicode 字符问题
【发布时间】:2012-04-24 19:51:44
【问题描述】:

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

【问题讨论】:

  • 这些是框架方法,因此在 C# 和 F# 之间没有区别。嘎嘎声就像处理字符串文字的编译器错误。记录你从 s.ToCharArray() 中得到的结果。
  • 1) Char.IsSurrogate 有 2 个签名 - 第二个允许使用字符串和位置; 2) let s = '\U0001D11E' 导致编译器错误

标签: c# unicode f# surrogate-pairs


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 谢谢,是的 Char.ConvertFromUtf32 在某些情况下可以用作解决方案,它肯定会带来限制(我不能在常量中以这种方式声明字符)
    • 您可以像这样破解常量:\uD834\uDD1E。它不是很可读,可能最好添加评论来描述那是什么,但总比没有好。
    【解决方案3】:

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

    我希望这会有所帮助。

    【讨论】:

    • 感谢您的问题描述,所以您认为问题在于 F# 中使用了不同的规范化。好的,但是如果 "\U0001D11E" 对我不起作用,我如何使用 F# 将代理字符添加到字符串中?
    • 我认为这个问题与规范化无关。实际上,像这样的字符串应该按原样解析和呈现,这肯定会发生。
    猜你喜欢
    • 1970-01-01
    • 2021-12-02
    • 2011-11-12
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    相关资源
    最近更新 更多