Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid writing regex match twice?

Tags:

f#

I have this code:

let main argv = 
let x="b"
match x with
| _ when Regex.Match(x,"a").Success=true->
    let a=Regex.Match(x,"a")
    Console.WriteLine(a.Groups.[0])
| _ when Regex.Match(x,"b").Success=true->
    let b=Regex.Match(x,"b")
    Console.WriteLine(b.Groups.[0])

I have to write Regex.Match(x,"a") and Regex.Match(x,"b") twice in the above code. Is there some way to write it only once?

like image 626
wang kai Avatar asked Mar 07 '23 08:03

wang kai


1 Answers

Go for active patterns:

let (|Match|_|) pattern input =
    let m = Regex.Match(input, pattern, RegexOptions.Singleline)
    if m.Success 
        then Some (m.Groups.[0])
        else None
// and use it:
match x with
| Match @"a text" a ->
    printfn "found a: %s" a
| Match @"b text" b ->
    printfn "found b: %s" b

You can go even further and make an active pattern that supports its own number of parsed values:

let (|Regex|_|) pattern input =
    let m = Regex.Match(input, pattern, RegexOptions.Singleline)
    if m.Success
        // List.tail is needed to skip the m.Groups.[0] that returns the entire parsed scope
        then [ for g in m.Groups -> g.Value ] |> List.tail |> Some
        else None

match x with
| Regex @"a (\w+)\s(\w+)" [ a1; a2 ] ->
    printfn "found A value: %s and %s" a1 a2
| Regex @"b (\w+)\s(\w+)\s(\w+)" [ b1; b2; b3 ] ->
    printfn "found B value: %s and %s and %s" b1 b2 b3

// this will be able to parse the following:
// "a foo bar"     ==> a1="foo" and a2="bar"
// "b foo bar baz" ==> b1="foo", b2="bar", and b3="baz"
like image 184
bytebuster Avatar answered Mar 16 '23 22:03

bytebuster