Created
November 22, 2011 16:49
-
-
Save anonymous/1386159 to your computer and use it in GitHub Desktop.
F# regex active patterns proposal #2 for fsharpx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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