I need help with p开发者_运维百科aternmatching in F#. I want to do this:
let y x =
match x with
| x.Contains("hi") -> "HELLO"
| x.Contains("hello") -> "HI"
| x -> x
But it doesn't work. What's wrong?
The easiest approach is to use a when guard in your match cases.
let y (x:string) =
match x with
| x when x.Contains("hi") -> "HELLO"
| x when x.Contains("hello") -> "HI"
| x -> x
Conditions that include method calls can be only written in the when
guard as pblasucci writes.
If you want to use some advanced F# features (e.g. if you need to write this a lot), then you can define active pattern to check for substring (but don't worry about this if you're just learning F#):
let (|Contains|_|) (what:string) (str:string) =
if str.Contains(what) then Some(str) else None
Then you can write something like (interestingly, you can also use nested patterns to check for multiple words, but the same thing could be written using &
pattern):
match "hello world" with
| Contains "hello" (Contains "world" str) ->
printfn "%s contains both hello and world!" str
| Contains "hello" str ->
printfn "%s contains only hello!" str
| _ -> ()
I think my answer here to a previous question may help you understand pattern matching a little better.
However, for what you are trying to do, I'd probably stick with simple if/then/else expressions:
let y x =
if x.Contains("hi") then "HELLO"
elif x.Contains("hello") then "HI"
else x
Creating a special Contains
active pattern like @Tomas Petricek shows is also an option, but I find that if I am actually going to be doing some serious string pattern matching, then I just stick with a couple faithful regex active patterns:
open System.Text.RegularExpressions
///Match the pattern using a cached interpreted Regex
let (|InterpretedMatch|_|) pattern input =
if input = null then None
else
let m = Regex.Match(input, pattern)
if m.Success then Some [for x in m.Groups -> x]
else None
///Match the pattern using a cached compiled Regex
let (|CompiledMatch|_|) pattern input =
if input = null then None
else
let m = Regex.Match(input, pattern, RegexOptions.Compiled)
if m.Success then Some [for x in m.Groups -> x]
else None
and for this problem, use them like so:
let y = function // shorthand for let y x = match x with ...
| CompiledMatch @"hi" _ -> "HELLO"
| CompiledMatch @"hello" _ -> "HI"
| x -> x
I like this because it covers Contains, StartsWith, EndsWith, Equals, and beyond with ease:
let y = function
| CompiledMatch @"^hi$" _ -> "Equals"
| CompiledMatch @"^hi" _ -> "StartsWith"
| CompiledMatch @"hi$" _ -> "EndsWith"
| CompiledMatch @"leadinghiending" _ -> "Beyond"
| CompiledMatch @"hi" _ -> "Contains"
| x -> x
(note that the literal strings, introduced by @, are not actually needed for any of these regex examples, but as a matter of habit, I always use them since you need them more often than not with regular expressions).
精彩评论