I want to write an F#.NET Boolean function named IsStrValid using a regex that decides whether a given string s confirms to the following rules or not:
s is 4-character longE.g.:
IsStrValid "A3B3" //true
IsStrValid "A3A3" //false
This is how far I've gotten; stuck at the conditional part (???):
let IsStrValid (s : string) =
Regex.IsMatch(s, @"^([ABC])([123])([ABC])(?(???)[123]|[???])$")
While regular expressions support backreferences, trying to do complex logic like 'if X then Y' is pretty difficult. You could do something like this with a negative lookahead assertion:
let IsStrValid (s : string) =
Regex.IsMatch(s, @"^([ABC][123])(?!\1)[ABC][123]$")
However, as Mathew suggests, if it gets more complicated than this, it's probably easier to simply test the conditions directly, like this:
let IsStrValid (s : string) =
let isLet i = Seq.exists ((=)s.[i]) ['A'; 'B'; 'C']
let isNum i = Seq.exists ((=)s.[i]) ['1'; '2'; '3']
(s.Length = 4) && (isLet 0) && (isNum 1) && (isLet 2) && (isNum 3) &&
(s.[0] <> s.[2]) || (s.[1] <> s.[3])
This sounds like a perfect application for conditionals, but they actually make this job more difficult, not less. It's much easier to do it the old-fashioned way, with lookaheads.
^
([ABC])
([123])
(?:
(?!\1)[ABC][123]
|
\1(?!\2)[123]
)
$
This implements your description almost verbatim. If the third character is one of the allowed letters, but not the same as the first one, grab it and any of the allowed digits. If the third character is the same as the first, grab it followed by one of the allowed digits, unless it's the same as the first digit.
But I think even that's more complex than it needs to be. It seems to me your requirements can be restated as two consecutive pairs of characters that match the regex [ABC][123], but must not match each other
^([ABC])([123])(?!\1\2)[ABC][123]$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With