【问题标题】:How to check if list of phrases exists in the text?如何检查文本中是否存在短语列表?
【发布时间】:2018-01-02 21:44:40
【问题描述】:

我一直在尝试创建一个过滤器,该过滤器使用递归函数和匹配模式检查文本中是否存在短语列表中的短语,但不知何故这似乎不起作用......也许有人可以给我提示原因?

let rec matchTails (tail1 : string list) (tail2 : string list) = 
    match tail1, tail2 with
        | h1::t1 , h2::t2 -> 
            if (h1=h2) then 
                matchTails t1 t2
            else
                false
        | _, [] -> false
        | [],_-> true

let rec check2 (textH: string) (textT: string list) (phrases: string list list) = 
    match phrases with 
    |[] -> ()
    | h :: t ->
        printfn "%s -- %s" (h.Head) (textH)
        match h with
        |x when x.Length = 1 && x.Head = textH -> 
            ()
        |x when x.Head = textH && (matchTails (textT) (x)) ->
            printfn "%s" (x.Head)
        | _ -> ()
        check2 (textH) (textT) (t)

let rec check (phrases : string list list) (text:string list) = 
    match text with
    | [] -> ()
    | h :: t ->
        check2 (h) (t) (phrases)
        check phrases t


let p = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]

let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]

函数调用:检查 p t

我已经编辑了我的问题并修复了一些错误,但是,通过这些列表,程序将 unit() 作为输出...

【问题讨论】:

  • 你的匹配表达式中有h2 = h2。这将始终评估为真。你是说h1 = h2 吗?

标签: string list text f#


【解决方案1】:

有一些提示:

  • matchTails 为

    返回不正确的结果
    matchTails [ "asdf1" ] [ "asdf" ] => true
    matchTails [ "asdf" ] [ "asdf"; "asdf1" ] => true
    matchTails [ ] [ "" ] => true
    

    我怀疑在所有这些情况下它都应该返回false。可能你想要的实现是:

    let rec matchTails (phrase : string list) (text : string list) = 
      match phrase, text with
      | h1 :: t1, h2 :: t2 -> if h1 = h2 then matchTails t1 t2
                              else false
      | [ ], _ -> true
      | _ -> false
    
    let matchTails_test () =
      if not (matchTails [ "" ] [ "" ]) then raise Exception()
      ...
    
  • check2 没有被递归调用,所以只检查第一个短语

  • check不递归调用,调用check2并返回

通常,尝试将问题分解为更小的函数并分别测试它们。您正在朝着正确的方向前进,缺少的是清楚每个功能应该做什么和测试用例。

更新:

注意check2 并没有真正返回任何值(它返回单位)。此外,它的功能与matchTails 重叠 - 它使用短语中的第一个单词检查头部,这就是matchTails 所做的。

check 也返回单位,() 表示单位。

所以让我们重写check:

let rec check (phrases : string list list) (text : string list) =
  if phrases |> List.exists (fun ph -> matchTails ph text) then
    true
  else
    match text with
    | [] -> false
    | _ :: tail -> check phrases tail

【讨论】:

  • 我已经编辑了我的问题,并修复了这些错误,但程序似乎找到了长度为 1 的短语,但没有找到更长的短语..
【解决方案2】:

虽然问题现在有been basically answered,但我想指出,它划分为子问题已经很充分了;令人震惊的是缺乏相关的测试,以及处理每个子问题的各个函数的一些描述性命名。

像这样命名(和测试)matchTails、check2 和 check 怎么样?

let ps = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]

startsWithPhrase ["hello"; "and"] t
containsPhrase ["free"; "cash"] t
containsAnyPhrase ps t

剧透:

let rec startsWithPhrase phrase text = 
    match phrase, text with
    | h1::t1, h2::t2 when h1 = h2 -> startsWithPhrase t1 t2
    | [], _-> true
    | _ -> false

let rec containsPhrase phrase text =
    startsWithPhrase phrase text ||
    match text with
    | _::tl -> containsPhrase phrase tl
    | [] -> false

let rec containsAnyPhrase phrases text =
    match phrases with
    | h::tl -> 
        containsPhrase h text ||
        containsAnyPhrase tl text
    | [] -> false

完全使用高级函数可能要容易得多,每个函数都代替一个递归循环。尽管这里的方法略有不同,将干草堆分成针大小的切片,并将每个切片与给定的短语进行比较。

let containsPhraseHL phrase text = 
    Seq.windowed (List.length phrase) text
    |> Seq.exists (Seq.forall2 (=) phrase)

containsPhraseHL ["free"; "cash"] t

let containsAnyPhraseHL phrases text =
    List.exists (fun phrase -> containsPhraseHL phrase text) phrases

containsAnyPhraseHL ps t

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 2021-06-02
    • 2019-09-28
    • 2010-12-21
    • 2019-01-19
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多