2016-07-18 1 views
2

Поскольку я не совсем доволен реализацией регулярного выражения F # для моего использования, я хотел реализовать так называемую цепочку регулярных выражений . Он в основном работает следующим образом:F # Regex matching chain

Данная строка s будет проверена, соответствует ли она первому шаблону. Если это так, он должен выполнить функцию, связанную с первым шаблоном. Если это не так, оно должно продолжаться со следующего.

Я пытался реализовать его следующим образом:

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

Другим подходом было бы сделать эту ориентированную на данные: поместите пары регулярных выражений в список и используйте 'List.tryPick' для запуска функции для первого соответствующего регулярного выражения. Это позволит вам динамически наращивать функции регулярных выражений. – TheQuickBrownFox

ответ

1

Для меня это похоже на то, что вы пытаетесь реализовать, это Active Patterns.

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

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 

Другой подход заключается в использовании того, что Федор называет Железнодорожное Oriented Programming:

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 не будет поддерживать трубопроводы, поскольку она имеет параметры с настройками.

Во-первых, посмотрите на определение трубы:

let (|>) x f = f x 

Из этого можно ясно видеть, что это выражение:

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

будет эквивалентно следующему:

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

Соответствует ли это вашей сигнатуре функции? Очевидно нет. В вашей сигнатуре пара текста/bool на первом месте и является частью тройки параметров вместе с шаблоном и функцией.

Чтобы заставить его работать, вы должны принять «конвейеру» параметр в кэрри форме и в прошлом:

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

Затем вы можете сделать трубопровод:

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

В качестве в стороне, я должен отметить, что ваш подход не очень, гм, функциональный. Вы основываете свою логику на побочных эффектах, что сделает вашу программу неконсолируемой и трудно тестируемой, и, вероятно, подвержена ошибкам. Вы не пользуетесь преимуществами F #, эффективно используя его как «C# с более сильным синтаксисом».

Кроме того, есть на самом деле хорошо изученные способы достижения желаемого. Во-первых, проверьте Railway-oriented programming (также известный как монадические вычисления).