Parsing 如何构造匹配表达式

Parsing 如何构造匹配表达式,parsing,command-line,f#,pattern-matching,Parsing,Command Line,F#,Pattern Matching,我允许这样一个命令行参数--10GB,其中--和GB是常量,但可以在常量值之间替换1、10或100等数字,如--5GB 我可以使用substr轻松解析字符串的开头和结尾,或者编写一个命令行解析器,但我想使用match。我只是不知道如何构造匹配表达式 let GB1 = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1)) let arg = argv.[0] let match_head = "--" let match_tail = "GB" le

我允许这样一个命令行参数
--10GB
,其中
--
GB
是常量,但可以在常量值之间替换1、10或100等数字,如
--5GB

我可以使用
substr
轻松解析字符串的开头和结尾,或者编写一个命令行解析器,但我想使用
match
。我只是不知道如何构造匹配表达式

let GB1     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1))
let arg = argv.[0]

let match_head = "--"
let match_tail  = "GB"

let parse_min_gb_arg arg =
    match arg with
    | match_head & match_tail -> cvt_gb_arg_to_int arg
    | _ -> volLib.GB1

我收到一条警告说,
\这条规则永远不会匹配。
应该如何构造what is a AND表达式?

我能想到的最好方法是使用部分活动模式:

let (|GbFormat|_|) (x:string) =
    let prefix = "--"
    let suffix  = "GB"
    if x.StartsWith(prefix) && x.EndsWith(suffix) then
        let len = x.Length - prefix.Length - suffix.Length
        Some(x.Substring(prefix.Length, len))
    else
        None

let parse_min_gb_arg arg =
    match arg with
    | GbFormat gb -> gb
    | _ -> volLib.GB1

parse_min_gb_arg "--42GB"

您不能在字符串上进行匹配,除非在整个值上进行匹配,例如,
match s with |“1”->1 |“2”->2…

解析开始和结束是最有效的方法,不需要太聪明(顺便说一句,这是一个普遍正确的语句)

但是如果您真的想使用模式匹配,这是绝对可能的,但是您必须为自己制作一些自定义匹配器(也称为“活动模式”)

首先,制作一个自定义匹配器,该匹配器将解析出由前缀和后缀包围的字符串的“中间”部分:

let (|StrBetween|_|) starts ends (str: string) =
  if str.StartsWith starts && str.EndsWith ends then 
    Some (str.Substring(starts.Length, str.Length - ends.Length - starts.Length))
  else 
    None
用法:

let x = match "abcd" with 
        | StrBetween "a" "d" s -> s
        | _ -> "nope"
// x = "bc"
let x = match "15" with 
        | Int i -> i
        | _ -> 0
// x = 15
然后制作一个自定义匹配器,该匹配器将解析出一个整数:

let (|Int|_|) (s: string) = 
    match System.Int32.TryParse s with 
    | true, i -> Some i 
    | _ -> None
用法:

let x = match "abcd" with 
        | StrBetween "a" "d" s -> s
        | _ -> "nope"
// x = "bc"
let x = match "15" with 
        | Int i -> i
        | _ -> 0
// x = 15
现在,将两者结合起来:

let x = match "--10GB" with 
        | StrBetween "--" "GB" (Int i) -> i 
        | _ -> volLib.GB1
// x = 10

模式的这种组合和嵌套能力是它们的主要功能:您可以用小的、易于理解的片段构建复杂的模式,并让编译器将其与输入匹配。这就是它被称为“模式匹配”的基本原因

只需使用正则表达式!(我从没想过我会这么说;))如果GB是一个常量,那么指定它感觉有点太棒了,但是恕我直言,为什么不使用命令行解析库,比如或,两者都很好。@s952163我同意你的建议,更正式地解析一个更正式的应用程序。你有点挫败了活动模式的全部意义:没有模式,它只是一个函数调用。也可以是一个函数,像
将gbFormat arg与| Some gb->gb | None->volLib.GB1
匹配一样使用。是的,你用“如果你真的想要”来预测它,我用“我能想出的最好的”来预测它,我们在说同样的话。我想你可能误解了我的评论。我想说的是,如果你要使用模式,你应该制作小的模式并将它们组合起来,而不是制作一个大的模式,一次完成所有事情。这也是一个具有普通功能的好策略。啊,我明白你的意思。在中烘焙值是没有意义的,否则您就不会编写它的用法,或者在match语句中进行描述。没有人考虑语法<代码>一些str.[start.Length..str.Length-ends.Length-1]是的,我不太喜欢它。