2012-04-12 9 views
10

Sto lavorando con stringhe che potrebbero contenere caratteri unicode sostitutivi (non BMP, 4 byte per carattere).Problema con caratteri unicode surrogati in F #

Quando uso il formato "\ Uxxxxxxxxv" per specificare il carattere surrogato in F # - per alcuni caratteri dà risultati diversi rispetto a C#. Per esempio:

C#:

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

Dà: Length: 2, is surrogate: True

F #:

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

Dà: Length: 2, is surrogate: false

Nota: alcuni caratteri surrogati funzionano in F # ("\ U0010011", "\ U00100011"), ma alcuni di essi non funzionano.

D: È un errore in F #? Come posso maniglia permesso caratteri Unicode surrogati in stringhe con F # (fa F # ha formato diverso, o solo il modo è quello di utilizzareChar.ConvertFromUtf32 0x1D11E)

Aggiornamento:
s.ToCharArray() dà per F # [| 0xD800; 0xDF41 |]; per C# { 0xD834, 0xDD1E }

+0

Questi sono metodi quadro in modo da non differiscono tra C# e F #. È come un bug del compilatore che gestisce la stringa letterale. Documenta cosa ottieni da s.ToCharArray(). –

+0

1) Char.IsSurrogate ha 2 firme - la seconda consente di usare stringa e posizione; 2) * let s = '\ U0001D11E' * risulta nell'errore del compilatore – Vitaliy

risposta

5

Ciò significa ovviamente che F # fa errore durante l'analisi di alcuni valori letterali stringa. Ciò è dimostrato dal fatto che il personaggio che hai menzionato non è BMP, e in UTF-16 dovrebbe essere rappresentato come una coppia di surrogati. I surrogati sono parole nell'intervallo 0xD800-0xDFFF, mentre nessuno dei caratteri nella stringa prodotta rientra in tale intervallo.

Ma l'elaborazione dei surrogati non cambia, poiché il quadro (ciò che è sotto il cofano) è lo stesso.Quindi hai già una risposta nella tua domanda - se hai bisogno di stringhe letterali con caratteri non BMP nel tuo codice, dovresti semplicemente usare Char.ConvertFromUtf32 invece della notazione \ UXXXXXXXX. E tutto il resto dell'elaborazione sarà lo stesso di sempre.

+0

Grazie, e sì Char.ConvertFromUtf32 potrebbe essere usato come soluzione in alcuni casi, sicuramente dà limiti (non potrei dichiarare i caratteri in questo modo nelle costanti) – Vitaliy

+0

Puoi modificare le costanti in questo modo: '' \ uD834 \ uDD1E'' . Non è molto leggibile, probabilmente è meglio aggiungere un commento che descriva cos'è, ma ancora meglio niente. –

+0

Grazie - questo funzionerà come soluzione temporanea – Vitaliy

1

Mi sembra che questo sia qualcosa collegato a diverse forme di normalizzazione. Sia in C# e in F # s.IsNormalized() restituisce vero Ma in C#

s.ToCharArray() ci dà {55348, 56606} // 0xD834, 0xDD1E

e in F #

s.ToCharArray() ci dà {65533, 57422} // 0xFFFD, 0xE04E

E, come probabilmente sapete System.Char.IsSurrogate è implementato nel modo seguente:

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

dove

HIGH_SURROGATE_START = 0x00d800; 
    LOW_SURROGATE_END = 0x00dfff; 

Quindi, in C# primo carattere (55348) è inferiore LOW_SURROGATE_END ma in F # primo carattere (65533) non è inferiore LOW_SURROGATE_END.

Spero che questo aiuti.

+0

Grazie per la descrizione del problema, quindi il problema che si pensa è con una diversa normalizzazione utilizzata in F #. Ok, ma come posso aggiungere il carattere surrogato alla stringa con F #, se * "\ U0001D11E" * non funziona per me? – Vitaliy

+0

Non penso che questo problema abbia nulla a che fare con la normalizzazione. In realtà, una stringa come questa dovrebbe essere solo analizzata e presentata così com'è, e questo è sicuramente ciò che accade. –

7

Questo è un bug noto nel compilatore F # fornito con VS2010 (e SP1); la correzione appare nei bit VS11, quindi se hai il VS11 Beta e usi il compilatore F # 3.0, vedrai questo comportamento come previsto.

(Se le altre risposte/commenti qui non forniscono una soluzione adatta, nel frattempo, fatemelo sapere.)

+0

Grazie - sì, la soluzione di @Andriy K funziona per me – Vitaliy