Multiple regex matches

beginners

#1

Hi,

I have a string that I know will match one (and only one) of three regexes. I want to try each regex in turn until a match is found. For two of the regexes it is sufficient to know that there is a match. The third regex has a capture group and returns an integer.
I have an active pattern for regex:

let (|Regex|_|) pattern input =
let m = Regex.Match(input, pattern)
if m.Success then Some(List.tail [ for g in m.Groups -> g.Value ])
else None

I’m new to F# and struggling for an idiomatic way to do this. I don’t really want to make a convoluted if-then-else expression,
Any help would be really appreciated.

Thanks


#2

You could create three active patterns that match the three regex patterns you want to match, then just match for them in the order you want. All the if/else will then contained in the active patterns. Having the if/else in the guards may look perfectly fine though, don’t be scared of using if/else theres nothing wrong with using them.


#3

Alternatively you could use FParsec instead of regex.

Example using FParsec:

open FParsec.CharParsers
open FParsec.Primitives

let p1 = skipString "string1" >>. spaces >>. pstring "foo"
let p2 = skipString "string2" >>. spaces >>. pstring "bar"
let p3 = skipString "string3" >>. spaces >>. pstring "baz"

let parser : Parser<string,unit> =
    p1 <|> p2 <|> p3

run parser "string2 bar"

This would successfully parse “bar”

Also, the smaller parsers could have been written using a computated expression which would look like this:

let parser1 = parse {
   do! skipString "string1"
   do! spaces
   let! x = pstring "foo"
   return x }

For your case (if I’m understanding you correctly) you could do something like this:

type MyType
  = Type1
  | Type2
  | Type3 of int

let p1 = skipString "string1" >>. spaces >>. pstring "foo" |>> fun _ -> Type1
let p2 = skipString "string2" >>. spaces >>. pstring "bar" |>> fun _ -> Type2
let p3 = skipString "string3" >>. spaces >>. pint32 |>> Type3

let parser : Parser<MyType,unit> =
  p1 <|> p2 <|> p3

match run parser "string3 1" with
| Success (Type1,_,_)     -> "first parser succeeded"
| Success (Type2,_,_)     -> "second parser succeeded"
| Success ((Type3 i),_,_) -> "third parser succeeded and here's the int: " + string i
| Failure (msg,_,_)       -> msg

#4

Hi, I want to ask how to process below strings:
“”"
estasdgfb 23435 fsdddgdf
sdasf345243
batch size 75
sadf2341
“”"
to fetch 75 after batch size?

Currently I will split the whole string and parse line by line with FParsec. I do not know if there is any better way.

Thanks


#5

I’ll try that thanks.