2012-04-12 5 views
10

Estoy trabajando con cadenas, que podrían contener caracteres sustitutos Unicode (no BMP, 4 bytes por carácter).Problema con caracteres unicode en sustitución en F #

Cuando uso el formato "\ Uxxxxxxxxv" para especificar el carácter sustituto en F # - para algunos caracteres da un resultado diferente que en el caso de C#. Por ejemplo:

C#:

string s = "\U0001D11E"; 
bool c = Char.IsSurrogate(s, 0); 
Console.WriteLine(String.Format("Length: {0}, is surrogate: {1}", s.Length, c)); 

Da: Length: 2, is surrogate: True

F #:

let s = "\U0001D11E" 
let c = Char.IsSurrogate(s, 0) 
printf "Length: %d, is surrogate: %b" s.Length c 

Da: Length: 2, is surrogate: false

Nota: algunos personajes sustitutos funcionan en F # ("\ U0010011", "\ U00100011"), pero algunos de ellos no funcionan.

P: ¿Esto es un error en F #? ¿Cómo puedo mango permitido caracteres Unicode sustitutas en las cadenas con F # (no F # tiene un formato diferente, o sólo la forma es utilizarChar.ConvertFromUtf32 0x1D11E)

Actualización:
s.ToCharArray() da para F # [| 0xD800; 0xDF41 |]; para C# { 0xD834, 0xDD1E }

+0

Estos son métodos marco por lo que no difieren entre C# y F #. Quacks como un error del compilador que maneja el literal de la cadena. Documente lo que obtiene de s.ToCharArray(). –

+0

1) Char.IsSurrogate tiene 2 firmas; la segunda permite usar la secuencia y la posición; 2) * let s = '\ U0001D11E' * da como resultado el error del compilador – Vitaliy

Respuesta

5

Eso obviamente significa que F # comete un error al analizar algunos literales de cadena. Eso está demostrado por el hecho de que el personaje que ha mencionado no es BMP, y en UTF-16 debería representarse como un par de sustitutos. Los sustitutos son palabras en el rango 0xD800-0xDFFF, mientras que ninguno de los caracteres en cadena producida cabe en ese rango.

Pero el procesamiento de sustitutos no cambia, ya que el marco (lo que está debajo del capó) es el mismo.De modo que ya tiene respuesta en su pregunta: si necesita cadenas literales con caracteres que no sean BMP en su código, debe usar Char.ConvertFromUtf32 en lugar de la notación \ UXXXXXXXX. Y todo el resto del procesamiento será el mismo que siempre.

+0

Gracias, y sí, Char.ConvertFromUtf32 podría usarse como solución en algunos casos, de seguro da limitación (no pude declarar caracteres de esa manera en constantes) – Vitaliy

+0

Puede hackear constantes como esta: '' \ uD834 \ uDD1E'' . No es muy legible, probablemente sea mejor agregar un comentario describiendo qué es eso, pero aún mejor que nada. –

+0

Gracias - esto funcionará como la solución – Vitaliy

1

Me parece que esto es algo relacionado con las diferentes formas de normalización. Tanto en C# y F # en s.IsNormalized() devuelve verdadero Pero en C#

s.ToCharArray() nos da {55348, 56606} // 0xD834, 0xDD1E

y en Fa #

s.ToCharArray() nos da {65533, 57422} // 0xFFFD, 0xE04E

Y como usted probablemente sabe System.Char.IsSurrogate se implementa de la siguiente manera:

public static bool IsSurrogate(char c) 
    { 
     return (c >= HIGH_SURROGATE_START && c <= LOW_SURROGATE_END); 
    } 

donde

HIGH_SURROGATE_START = 0x00d800; 
    LOW_SURROGATE_END = 0x00dfff; 

Así que en C# primer carácter (55348) es menor que LOW_SURROGATE_END pero en F # primer carácter (65533) no es menor que LOW_SURROGATE_END.

Espero que esto ayude.

+0

Gracias por la descripción del problema, por lo que el problema que usted piensa es con una normalización diferente utilizada en F #. Bien, pero ¿cómo puedo agregar un personaje sustituto en una cadena con F #, si * "\ U0001D11E" * no funciona para mí? – Vitaliy

+0

No creo que este problema tenga algo que ver con la normalización. En realidad, una cadena como esta debería ser analizada y presentada tal como está, y eso es definitivamente lo que sucede. –

7

Este es un error conocido en el compilador F # que se envió con VS2010 (y SP1); la corrección aparece en los bits VS11, por lo tanto, si tiene VS1 Beta y usa el compilador F # 3.0, verá que esto se comporta como se esperaba.

(Si las otras respuestas/comentarios aquí no le proporcionan una solución adecuada, mientras tanto, que me haga saber.)

+0

Gracias, sí, la solución @Andriy K funciona para mí – Vitaliy