Проблема с суррогатными символами Юникода в F#

Я работаю со строками, которые могут содержать суррогатные символы Юникода (не BMP, 4 байта на символ).

Когда я использую формат "\Uxxxxxxxxv" для указания суррогатного символа в F# - для некоторых символов это дает другой результат, чем в случае 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

Ф#:

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# (есть ли у F# другой формат или только способ использования Char.ConvertFromUtf32 0x1D11E)

Обновление:
s.ToCharArray() дает для F# [| 0xD800; 0xDF41 |]; для С# { 0xD834, 0xDD1E }


person Vitaliy    schedule 12.04.2012    source источник
comment
Это методы фреймворка, поэтому они не отличаются между C# и F#. Крякает, как ошибка компилятора, обрабатывающая строковый литерал. Документируйте, что вы получаете от s.ToCharArray().   -  person Hans Passant    schedule 12.04.2012
comment
1) Char.IsSurrogate имеет 2 подписи - вторая позволяет использовать строку и позицию; 2) let s = '\U0001D11E' приводит к ошибке компилятора   -  person Vitaliy    schedule 12.04.2012


Ответы (3)


Очевидно, это означает, что F# допускает ошибку при анализе некоторых строковых литералов. Это подтверждает тот факт, что упомянутый вами символ не является BMP, и в UTF-16 он должен быть представлен как пара суррогатов. Суррогаты — это слова в диапазоне 0xD800-0xDFFF, в то время как ни один из символов в создаваемой строке не подходит для этого диапазона.

Но обработка суррогатов не меняется, так как фреймворк (то, что под капотом) тот же. Итак, у вас уже есть ответ на ваш вопрос - если вам нужны строковые литералы с символами, отличными от BMP, в вашем коде, вы должны просто использовать Char.ConvertFromUtf32 вместо нотации \UXXXXXXXX. А вся остальная обработка будет как всегда.

person Andriy K    schedule 12.04.2012
comment
Спасибо, и да, Char.ConvertFromUtf32 можно использовать как решение в некоторых случаях, это наверняка дает ограничение (я не мог объявлять символы таким образом в константах) - person Vitaliy; 12.04.2012
comment
Вы можете взломать константы следующим образом: \uD834\uDD1E. Не очень читабельно, наверное, лучше добавить комментарий с описанием, что это такое, но все же лучше, чем ничего. - person Andriy K; 12.04.2012

Это известная ошибка в компиляторе F#, который поставляется с VS2010 (и SP1); исправление появляется в битах VS11, поэтому, если у вас есть бета-версия VS11 и вы используете компилятор F # 3.0, вы увидите, что это ведет себя так, как ожидалось.

(Если другие ответы/комментарии здесь пока не предоставляют вам подходящего обходного пути, дайте мне знать.)

person Brian    schedule 12.04.2012

Мне кажется, что это что-то связанное с разными формами нормализации. Как в C#, так и в F# s.IsNormalized() возвращает true Но в C#

s.ToCharArray() дает нам {55348, 56606} //0xD834, 0xDD1E

и в фа#

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.

Надеюсь, это поможет.

person VMykyt    schedule 12.04.2012
comment
Спасибо за описание проблемы, поэтому проблема, по вашему мнению, связана с другой нормализацией, используемой в F#. Хорошо, но как я могу добавить суррогатный символ в строку с помощью F#, если \U0001D11E у меня не работает? - person Vitaliy; 12.04.2012
comment
Я не думаю, что эта проблема имеет какое-либо отношение к нормализации. На самом деле, подобная строка должна быть просто проанализирована и представлена ​​как есть, и это определенно то, что происходит. - person Andriy K; 12.04.2012