由于我对F#的正则表达式实现并不完全满意,我想实现一个所谓的正则表达式链。它基本上如下工作:
将检查给定字符串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
问题是,这段代码无效,因为正向管道运算符似乎没有管道元组或者不喜欢我的实现' design'。
我的问题是:我可以轻松修复上面的代码,还是应该实现其他类型的正则表达式链?
答案 0 :(得分:6)
你的函数RegexMatch
不支持管道,因为它有参数元组。
首先,看一下管道的定义:
let (|>) x f = f x
由此可以清楚地看到这个表达式:
("text", true)
|> RegexMatch("pattern", fun x -> ...)
等同于:
RegexMatch("pattern", fun x -> ...) ("text", true)
这是否符合您的功能签名?显然不是。在您的签名中,text / bool对首先出现,并且是参数的三倍,以及模式和功能。
为了使它工作,你需要采取"管道"咖喱形式和最后的参数:
let RegexMatch p f (s, c) = ...
然后你可以做管道:
("input", true)
|> RegexMatch "pattern1" (fun x -> ...)
|> RegexMatch "pattern2" (fun x -> ...)
|> RegexMatch "pattern3" (fun x -> ...)
顺便说一句,我必须注意你的方法不是很好,嗯,功能性。您将整个逻辑基于副作用,这将使您的程序无法组合并且难以测试,并且可能容易出错。你并没有从F#中获益,有效地将它作为#34; C#使用更好的语法"。
此外,实际上有很多研究方法可以达到你想要的效果。例如,查看Railway-oriented programming(也称为monadic计算)。
答案 1 :(得分: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
另一种方法是使用Fyodor所指的铁路导向编程:
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