Skip to content

Instantly share code, notes, and snippets.

Created November 22, 2011 16:49
Show Gist options
  • Save anonymous/1386159 to your computer and use it in GitHub Desktop.
Save anonymous/1386159 to your computer and use it in GitHub Desktop.
F# regex active patterns proposal #2 for fsharpx
namespace Extensions
open System.Text.RegularExpressions
///Regex extensions
module Regex =
type ActiveMatch =
{
Match: Match
MatchValue: string
Groups: Group list
OptionalGroups: (Group option) list
GroupValues: string list
OptionalGroupValues: (string option) list
}
let (|Match|_|) flags pattern input =
match input with
| null -> None //Regex.Match will throw with null input, we return None instead
| _ ->
//using the static Regex.Match takes advantage of Regex caching
match Regex.Match(input, pattern, flags) with
| m when m.Success ->
//n.b. the head value of m.Groups is the match itself, which we discard
//n.b. if a group is optional and doesn't match, it's Value is ""
let groups = [for x in m.Groups -> x].Tail
let optionalGroups = groups |> List.map (fun x -> if x.Success then Some(x) else None)
let groupValues = groups |> List.map (fun x -> x.Value)
let optionalGroupValues = optionalGroups |> List.map (function None -> None | Some(x) -> Some(x.Value))
Some({ Match=m
MatchValue=m.Value
Groups=groups
OptionalGroups=optionalGroups
GroupValues=groupValues
OptionalGroupValues=optionalGroupValues })
| _ -> None
module Compiled =
//note: if we need to support Silverlight and other reduced runtimes that don't support RegexOptions.Compiled,
//then it would be nice for us to detect that and fall back on RegexOptions.None here (compiling is just an
//optimization detail, doesn't change behavior of regex otherwise, so doing this fall back allows library
//users to share code between their full vs. silverlight applications more easily).
let (|Match|_|) = (|Match|_|) RegexOptions.Compiled
module Interpreted =
let (|Match|_|) = (|Match|_|) RegexOptions.None
module RegexTests =
let ``MatchWithGroupValues null input OK`` =
match null with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { GroupValues=["john"; ""; "smith"] } ->
false
| _ -> true
//unlike in other version
let ``MatchWithGroupValues no groups IS OK`` =
try
match "john smith" with
| Regex.Match RegexOptions.None "^john smith$" { MatchValue="john smith"; GroupValues=_ } -> true
| _ -> true
with
| :? System.ArgumentException -> false
let ``MatchWithGroupValues success`` =
match "john smith" with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { MatchValue="john smith"; GroupValues=["john"; ""; "smith"] } ->
true
| _ -> false
let ``MatchWithGroups success`` =
match "john smith" with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { MatchValue="john smith"; OptionalGroupValues=[Some "john"; None; Some "smith"] } ->
true
| _ -> false
let ``GroupValues success`` =
match "john smith" with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { GroupValues=["john"; ""; "smith"] }->
true
| _ -> false
let ``Groups success`` =
match "john smith" with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { OptionalGroupValues=[Some "john"; None; Some "smith"] }->
true
| _ -> false
let ``Match success`` =
match "john smith" with
| Regex.Match RegexOptions.None "^(\w*) (\w* )?(\w*)$" { MatchValue="john smith" } ->
true
| _ -> false
let ``Compiled.GroupValues success`` =
match "john smith" with
| Regex.Compiled.Match "^(\w*) (\w* )?(\w*)$" { GroupValues=["john"; ""; "smith"] } ->
true
| _ -> false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment