2015-03-31 8 views
7

Sto lavorando a un progetto secondario in F # che implica il porting di codice C# esistente su F # e apparentemente ho notato una differenza nel modo in cui le espressioni regolari vengono gestite tra le due lingue (sto postando questo spero di scoprire che sto solo facendo qualcosa di sbagliato).Impossibile trovare il rilevamento di coppie di surrogati

Questa funzione secondaria rileva semplicemente le coppie surrogate utilizzando il trucco di espressione regolare delineato here. Ecco l'implementazione corrente:

let isSurrogatePair input = 
    Regex.IsMatch(input, "[\uD800-\uDBFF][\uDC00-\uDFFF]") 

Se dunque io eseguo contro una coppia di surrogati noto come questo:

let result = isSurrogatePair "野" 
printfn "%b" result 

ottengo false nella finestra FSI.

Se io uso l'equivalente C#:

public bool IsSurrogatePair(string input) 
{ 
    return Regex.IsMatch(input, "[\uD800-\uDBFF][\uDC00-\uDFFF]"); 
} 

E lo stesso valore d'ingresso, I (correttamente) ottengo true indietro.

È un vero problema? Sto semplicemente facendo qualcosa di sbagliato nella mia implementazione F #?

risposta

8

Sembra esserci un errore nel modo in cui F # codifica caratteri Unicode sfuggiti.
Ecco dalla F # Interactive (notare gli ultimi due risultati):

> "\uD500".[0] |> uint16 ;; 
val it : uint16 = 54528us 
> "\uD700".[0] |> uint16 ;; 
val it : uint16 = 55040us 
> "\uD800".[0] |> uint16 ;; 
val it : uint16 = 65533us 
> "\uD900".[0] |> uint16 ;; 
val it : uint16 = 65533us 

Fortunatamente, questa soluzione funziona:

> let s = new System.String([| char 0xD800 |]) 
s.[0] |> uint16 
;; 

val s : System.String = "�" 
val it : uint16 = 55296us 

Sulla base di tale constatazione, posso costruire un corretto (o, meglio, workarounded) versione di isSurrogatePair:

let isSurrogatePair input = 
    let chrToStr code = new System.String([| char code |]) 
    let regex = "[" + (chrToStr 0xD800) + "-" + (chrToStr 0xDBFF) + "][" + (chrToStr 0xDC00) + "-" + (chrToStr 0xDFFF) + "]" 
    Regex.IsMatch(input, regex) 

Questa versione restituisce correttamente true per il vostro input.

ho appena presentato questo problema su GitHub: https://github.com/fsharp/fsharp/issues/399

2

sembra che questo sia un legittimo F # bug, nessun argomento lì. Volevo solo suggerire qualche soluzione alternativa.


Non incorporare i caratteri problema nella stringa stessa, specificarli utilizzando il normale supporto Unicode di regex. Il modello di espressione regolare per abbinare unicode Codepoint XXXX è \uXXXX, quindi basta sfuggire al tuo backslash o utilizzare una stringa verbatim:

Regex.IsMatch(input, "[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]") 
// or 
Regex.IsMatch(input, @"[\uD800-\uDBFF][\uDC00-\uDFFF]") 

Usa supporto integrato regex per i blocchi unicode:

// high surrogate followed by low surrogate 
Regex.IsMatch(input, @"(\p{IsHighSurrogates}|\p{IsHighPrivateUseSurrogates})\p{IsLowSurrogates}") 

o immobili

// 2 characters, each of which is half of a surrogate pair 
// (maybe could give false-positive if both are, e.g. low-surrogates) 
Regex.IsMatch(input, @"\p{Cs}{2}") 
Problemi correlati