7

私は、既存の C# コードを F# に移植することを含む F# のマイナーなサイド プロジェクトに取り組んでおり、2 つの言語間で正規表現がどのように処理されるかの違いに出くわしたようです (うまくいけば、私が間違ったことをしているだけです)。

このマイナーな機能は、ここで概説されている正規表現のトリックを使用してサロゲート ペアを検出するだけです。現在の実装は次のとおりです。

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

次に、次のような既知のサロゲートペアに対して実行すると:

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

falseFSI ウィンドウに入ります。

同等の C# を使用する場合:

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

そして、同じ入力値、私は(正しく)true戻ってきます。

これは本当の問題ですか?F# の実装で何か間違ったことをしているだけですか?

4

2 に答える 2

8

F# がエスケープされた Unicode 文字をエンコードする方法にバグがあるようです。
これは F# Interactive からのものです (最後の 2 つの結果に注意してください)。

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

その発見に基づいて、修正された(または、むしろ回避された)バージョンを構築できます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/Microsoft/visualfsharp/issues/338

于 2015-03-31T04:26:28.717 に答える
3

これは正当な 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}")
于 2015-04-01T04:43:57.970 に答える