2016-07-18 2 views
2

F#の正規表現の実装に満足していないので、正規表現のチェーンを実装したいと考えていました。F#Regexのマッチングチェーン

与えられた文字列sが最初のパターンと一致するかどうかがチェックされます。そうであれば、それは第1のパターンに関連する機能を実行すべきである。そうでない場合は、次のものを続ける必要があります。

次のように私はそれを実装しようとした:

let RegexMatch ((s : string, c : bool), p : string, f : GroupCollection -> unit) = 
    if c then 
     let m = Regex.Match(s, p) 
     if m.Success then 
      f m.Groups 
      (s, false) 
     else (s, c) 
    else (s, c) 


("my input text", true) 
|> RegexMatch("pattern1", fun g -> ...) 
|> RegexMatch("pattern2", fun g -> ...) 
|> RegexMatch("pattern3", fun g -> ...) 
|> .... // more patterns 
|> ignore 

を問題は、このコードは、「デザイン」、前方パイプオペレータはパイプのタプルには思われないよう、無効であるか、私の実装を好きではないということであり、 。

私の質問は:私はこのコードを簡単に修正することができますか、むしろ他の種類の正規表現チェーンを実装する必要がありますか?

+2

「*として、私はF#の正規表現の実装にはまったく満足していません。 "F#は正規表現の実装がありません。 .NETは、.NET Coreは、Monoは行いますが、F#は正規表現が何であるかを意識していません。 – ildjarn

+0

もう1つのアプローチは、データ指向にすることです:正規表現の関数の組をリストに入れ、 'List.tryPick'を使って最初に一致する正規表現の関数を実行します。これにより正規表現関数の場合を動的に構築できます。 – TheQuickBrownFox

答えて

1

私には、実装しようとしているように聞こえるのはActive Patternsです。あなたが正規表現パターンマッチングを行うために規則的なパターンマッチング構文を使用することができますアクティブパターン使用

let (|RegEx|_|) p i = 
    let m = System.Text.RegularExpressions.Regex.Match (i, p) 
    if m.Success then 
    Some m.Groups 
    else 
    None 

[<EntryPoint>] 
let main argv = 
    let text = "123" 
    match text with 
    | RegEx @"\d+" g -> printfn "Digit: %A" g 
    | RegEx @"\w+" g -> printfn "Word : %A" g 
    | _    -> printfn "Not recognized" 
    0 

に別のアプローチは、フョードルは鉄道指向プログラミングといいものを使用することです:

type RegexResult<'T> = 
    | Found  of 'T 
    | Searching of string 

let lift p f = function 
    | Found v  -> Found v 
    | Searching i -> 
    let m = System.Text.RegularExpressions.Regex.Match (i, p) 
    if m.Success then 
     m.Groups |> f |> Found 
    else 
     Searching i 

[<EntryPoint>] 
let main argv = 
    Searching "123" 
    |> lift @"\d+" (fun g -> printfn "Digit: %A" g) 
    |> lift @"\w+" (fun g -> printfn "Word : %A" g) 
    |> ignore 
    0 
6

関数RegexMatchは、パラメータがタプルされているため、配管をサポートしません。

("text", true) 
|> RegexMatch("pattern", fun x -> ...) 

これに相当します:1は、この表現がいることがわかり明確にすることができ、このことから

let (|>) x f = f x 

まず、パイプの定義を見て

RegexMatch("pattern", fun x -> ...) ("text", true) 

これは機能の署名と一致していますか?明らかにそうではありません。あなたの署名では、text/boolのペアが最初に来て、パターンと関数と共に3倍のパラメータの一部です。

("input", true) 
|> RegexMatch "pattern1" (fun x -> ...) 
|> RegexMatch "pattern2" (fun x -> ...) 
|> RegexMatch "pattern3" (fun x -> ...) 

let RegexMatch p f (s, c) = ... 

は、その後、あなたが配管を行うことができます。

はあなたが取る必要があり、それを動作させるためにカレー風味の形でパラメータと最後の「パイプ」さて、私はあなたのアプローチが非常に、ああ、ではないことに注意する必要があります。あなたは全体のロジックを副作用に基づいているので、あなたのプログラムは構成可能ではなく、テストするのが難しく、おそらくバグが発生しやすくなります。あなたはF#の利点を有効に活用しておらず、効果的に「C#with nicer syntax」を使用しています。

また、実際には、あなたが望むものを達成するために十分に研究された方法があります。 1つは、Railway-oriented programming(モナディック計算とも呼ばれます)を参照してください。