代码之家  ›  专栏  ›  技术社区  ›  Joel Mueller

F#字符串模式与通配符匹配

  •  5
  • Joel Mueller  · 技术社区  · 16 年前

    我正在尝试编写一个函数,该函数接受通配符、模式字符串和输入字符串作为参数。如果模式与输入不匹配,则函数返回 None . 如果模式与输入匹配,则函数返回 Some(str) str 输入字符串的任何部分与模式字符串中可能存在的任何通配符匹配。

    我已经基本完成了这项工作,稍后我将包含代码。我编写了一个通用模式匹配函数,它可以处理任何支持相等的通用列表,然后是一个助手函数,它接受字符串并将字符列表传递给通用函数。这一切都是可行的,除了一件事:模式字符串中对多个通配符的支持不是很好——它会获取每个通配符的匹配项,并将它们连接到输出中的单个字符串中。

    例如:

    > strMatch '*' "foo" "bar";;
    val it : string option = None
    
    > strMatch '*' "test" "test";;
    val it : string option = Some ""
    
    > strMatch '*' "functional programming is *" "functional programming is fun";;
    val it : string option = Some "fun"
    
    > strMatch '*' "* and *" "you and me";;
    val it : string option = Some "youme"
    

    let rec doMatch (wildcard:'a) (pat:'a list) (input:'a list) : 'a list option =
        let singleMatch p i =
            match (p, i) with
            | phd :: ptl, ihd :: itl ->
                if phd = wildcard then
                    match doMatch wildcard ptl itl with
                    | None -> None
                    | Some x -> Some(ihd :: x)
                else None
            | _ -> None
    
        let longerMatch p i =
            match (p, i) with
            | phd :: ptl, ihd :: itl ->
                if phd = wildcard then
                    match doMatch wildcard p itl with
                    | None -> None
                    | Some x -> Some(ihd :: x)
                else None
            | _ -> None
    
        match (pat, input) with
        | [], [] -> Some([])
        | [], _::_ -> None
        | _::_, [] -> None
        | phd :: ptl, ihd :: itl ->
            if phd <> wildcard then
                if phd = ihd then doMatch wildcard ptl itl
                else None
            else
                match singleMatch pat input with
                | Some x -> Some(x)
                | None -> longerMatch pat input
    
    let strMatch (wildcard:char) (pat:string) (input:string) =
        match doMatch wildcard (List.ofSeq pat) (List.ofSeq input) with
        | None -> None
        | Some x -> Some(new string(Array.ofList x))
    

    您可能已经猜到了,但这是F#中Eliza聊天机器人实现的一部分。

    1 回复  |  直到 16 年前
        1
  •  4
  •   Brian    16 年前

    从设计的角度来看,我喜欢返回

    'a list option
    

    在哪里。

    None              // it did not match
    Some[]            // matched, input had 0 wildcards
    Some["foo";"bar"] // matched, input has 2 wildcards, "foo" matched 1st, "bar" 2nd
    

    (我不清楚在你的长篇博文中是否有更深层次的问题。)

    编辑

    'a list list option
    

    因为“a”是一个字符,“a”列表就像一个字符串,我们需要一个字符串列表。singleMatch将启动一个新的字符串列表,而longerMatch将考虑当前字符串的前面。

    let rec doMatch (wildcard:'a) (pat:'a list) (input:'a list) 
               : 'a list list option =
        let singleMatch p i =
            match (p, i) with
            | phd :: ptl, ihd :: itl ->
                if phd = wildcard then
                    match doMatch wildcard ptl itl with
                    | None -> None
                    | Some xs -> Some([ihd]::xs)
                else None
            | _ -> None
    
        let longerMatch p i =
            match (p, i) with
            | phd :: ptl, ihd :: itl ->
                if phd = wildcard then
                    match doMatch wildcard p itl with
                    | None -> None
                    | Some ([]) -> Some([[ihd]])
                    | Some (x::xs) -> Some((ihd :: x)::xs)
                else None
            | _ -> None
    
        match (pat, input) with
        | [], [] -> Some([])
        | [], _::_ -> None
        | _::_, [] -> None
        | phd :: ptl, ihd :: itl ->
            if phd <> wildcard then
                if phd = ihd then doMatch wildcard ptl itl
                else None
            else
                match singleMatch pat input with
                | Some x -> Some(x)
                | None -> longerMatch pat input
    
    let strMatch (wildcard:char) (pat:string) (input:string) =
        match doMatch wildcard (List.ofSeq pat) (List.ofSeq input) with
        | None -> None
        | Some x -> Some(x|>List.map (fun chList -> new string(Array.ofList chList)))
    
    printfn "%A" (strMatch '*' "foo" "bar")
    printfn "%A" (strMatch '*' "test" "test")
    printfn "%A" (strMatch '*' "functional programming is *" 
                               "functional programming is fun")
    printfn "%A" (strMatch '*' "* and *" "you and me")