2015-03-31 1 views
7

Я работаю над проектом второстепенной стороны в F #, который включает перенос существующего кода C# на F #, и я, похоже, обнаружил разницу в том, как регулярные выражения обрабатываются между двумя языками (я отправляю это, надеюсь, узнаю, что я просто делаю что-то не так).Ошибка обнаружения суррогатной пары

Эта второстепенная функция просто обнаруживает суррогатные пары, используя трюк регулярного выражения, обозначенный here. Вот текущая реализация:

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

Если я затем выполнить его против известного суррогатной пары, как это:

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

я false в окне FSI.

Если я использую эквивалент C#:

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

И такое же значение входного сигнала, I (правильно) получить true обратно.

Это настоящая проблема? Я просто делаю что-то не так в моей реализации F #?

ответ

8

Возможно, существует ошибка в том, как F # кодирует экранированные символы Unicode.
Вот из F # Interactive (обратите внимание на последние два результата):

> "\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 регулярного выражения. Регулярное выражение шаблона, чтобы соответствовать юникоду элемента код XXXX является \uXXXX, так что просто избежать ваших обратных слэшей или использовать дословную строку:

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

Использование встроенного регулярных выражений поддержки Юникода блоки:

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