2015-03-31 161 views
7

我正在研究F#中的一個次要項目,它涉及將現有的C#代碼移植到F#,而且我似乎遇到了兩種語言之間處理正則表達式的差異(我正在發佈這希望找出我只是做錯了什麼)。代理對檢測失敗

這個次要功能只是使用正則表達式技巧here簡單地檢測代理對。下面是當前實現:

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

如果我然後執行它與已知的代理對這樣的:

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

我在FSI窗口得到false

如果我使用等效C#:

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

而同樣的輸入值,I(正確)獲得true回來。

這是一個真正的問題?我只是在我的F#實現中做錯了什麼?

回答

8

F#如何編碼轉義的Unicode字符似乎存在一個錯誤。
從F#互動這裏的(注意最後兩個結果):

> "\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 

幸運的是,這種解決方法的工作原理:

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

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

基於這一發現,我可以構建一個糾正(或者,更確切地說, workarounded)版本的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) 

此版本的正確返回true您的輸入。

我剛剛提交GitHub上這個問題:https://github.com/fsharp/fsharp/issues/399

2

看來,這是一個合法的F#錯誤,沒有參數那裏。只是想提出一些替代解決方法。


不要在字符串本身中嵌入問題字符,請使用正則表達式的普通unicode支持來指定它們。正則表達式匹配模式的Unicode碼點XXXX\uXXXX,所以才逃過你的反斜線或使用逐字字符串:

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

使用內置的正則表達式支持unicode的塊:

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

或屬性

// 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}")