正则表达式 – F#使用活动模式映射正则表达式匹配
我发现使用正则表达式使用Active Patterns的这篇有用的文章:
http://www.markhneedham.com/blog/2009/05/10/f-regular-expressionsactive-patterns/ 文章中使用的原始代码段是: open System.Text.RegularExpressions let (|Match|_|) pattern input = let m = Regex.Match(input,pattern) in if m.Success then Some (List.tl [ for g in m.Groups -> g.Value ]) else None let ContainsUrl value = match value with | Match "(http://S+)" result -> Some(result.Head) | _ -> None 如果至少找到一个网址和该网址是什么(如果我正确地理解了该片段),那会让你知道 然后在评论部分Joel建议这个修改:
试图结合所有这一切后,我想出了以下代码: let testString = "http://www.bob.com http://www.b.com http://www.bob.com http://www.bill.com" let (|Match|_|) pattern input = let re = new Regex(pattern) let m = re.Match(input) in if m.Success then Some ((re.GetGroupNames() |> Seq.map (fun n -> (n,m.Groups.[n])) |> Seq.filter (fun (n,g) -> g.Success) |> Seq.map (fun (n,g) -> (n,g.Value)) |> Map.ofSeq)) else None let GroupMatches stringToSearch = match stringToSearch with | Match "(http://S+)" result -> printfn "%A" result | _ -> () GroupMatches testString;; 当我在交互式会话中运行我的代码时,这是什么输出:
我试图实现的结果将如下所示:
基本上是发现每个唯一匹配的映射,后跟在文本中找到特定匹配字符串的次数的计数. 如果你认为我要走错路,请随时提出一个完全不同的做法.我对Active Patterns和Regular Expression都有些新意,所以我不知道在哪里开始尝试解决这个问题. 我也想出了这个,基本上我将在C#中翻译成F#. let testString = "http://www.bob.com http://www.b.com http://www.bob.com http://www.bill.com" let matches = let matchDictionary = new Dictionary<string,int>() for mtch in (Regex.Matches(testString,"(http://S+)")) do for m in mtch.Captures do if(matchDictionary.ContainsKey(m.Value)) then matchDictionary.Item(m.Value) <- matchDictionary.Item(m.Value) + 1 else matchDictionary.Add(m.Value,1) matchDictionary 运行时返回这个:
这基本上是我正在寻找的结果,但是我正在尝试学习这样做的功能方式,我认为应该包括活动模式.如果它比我的第一次尝试更有意义,可以尝试“功能化”这一点. 提前致谢, 短发
有趣的东西,我想你正在探索的一切都是有效的. (部分)正则表达式匹配的活动模式确实非常好.特别是当你有一个你想要匹配多个替代案例的字符串.我建议使用更复杂的正则表达式活动模式的唯一方法是,给予更多描述性名称,可能构建不同目的的不同正则表达式活动模式的集合.
至于你的C#到F#的例子,你可以有功能的解决方案没有活动的模式,例如 let testString = "http://www.bob.com http://www.b.com http://www.bob.com http://www.bill.com" let matches input = Regex.Matches(input,"(http://S+)") |> Seq.cast<Match> |> Seq.groupBy (fun m -> m.Value) |> Seq.map (fun (value,groups) -> value,(groups |> Seq.length)) //FSI output: > matches testString;; val it : seq<string * int> = seq [("http://www.bob.com",2); ("http://www.b.com",1); ("http://www.bill.com",1)] 更新 为什么这个特定的例子没有活动模式的工作正常的原因是因为1)你只是测试一个模式,2)你是动态处理的匹配. 对于一个现实世界的活动模式的例子,我们考虑一种情况,其中1)我们正在测试多个正则表达式,2)我们正在测试一个与多个组的正则表达式匹配.对于这些情况,我使用以下两个活动模式,这比您显示的第一个匹配活动模式(我不丢弃匹配中的第一个组)更为通用,我返回组对象的列表,而不仅仅是它们值 – 一个使用编译的正则表达式选项用于静态正则表达式模式,一个使用解释的regex选项用于动态正则表达式模式).因为.NET正则表达式API是如此的特征填充,您从活动模式返回的内容真的取决于您所发现的有用.但是返回一个列表的东西是好的,因为那时你可以在该列表中进行模式匹配. let (|InterpretedMatch|_|) pattern input = if input = null then None else let m = Regex.Match(input,pattern) if m.Success then Some [for x in m.Groups -> x] else None ///Match the pattern using a cached compiled Regex let (|CompiledMatch|_|) pattern input = if input = null then None else let m = Regex.Match(input,pattern,RegexOptions.Compiled) if m.Success then Some [for x in m.Groups -> x] else None 还要注意这些活动模式如何考虑不匹配,而不是抛出异常. 好的,所以让我们来分析一下名字.我们有以下要求: >必须有名字和姓氏 首先我们将定义以下记录: type Name = {First:string; Middle:option<string>; Last:string} 那么我们可以在一个解析名称的函数中非常有效地使用我们的正则表达式活动模式: let parseName name = match name with | CompiledMatch @"^(w+) (w+) (w+)$" [_; first; middle; last] -> Some({First=first.Value; Middle=Some(middle.Value); Last=last.Value}) | CompiledMatch @"^(w+) (w+)$" [_; first; last] -> Some({First=first.Value; Middle=None; Last=last.Value}) | _ -> None 注意我们在这里获得的关键优势之一,一般来说,模式匹配的情况是,我们能够同时测试输入与正则表达式匹配,并分解返回的组列表. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |