10

我正在学习 F#,并且我已经开始使用序列和match表达式。

我正在编写一个网络爬虫,它通过类似于以下内容的 HTML 进行查看,并<span>在该类的父paging级中获取最后一个 URL。

<html>
<body>
    <span class="paging">
        <a href="http://google.com">Link to Google</a>
        <a href="http://TheLinkIWant.com">The Link I want</a>
    </span>
</body>
</html>

我尝试获取最后一个 URL 如下:

type AnHtmlPage = FSharp.Data.HtmlProvider<"http://somesite.com">

let findMaxPageNumber (page:AnHtmlPage)= 
    page.Html.Descendants()
    |> Seq.filter(fun n -> n.HasClass("paging"))
    |> Seq.collect(fun n -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
    |> Seq.last
    |> fun n -> n.AttributeValue("href")

但是,当我正在搜索的课程不在页面上时,我遇到了问题。特别是我得到 ArgumentExceptions 的消息:Additional information: The input sequence was empty.

paging我的第一个想法是构建另一个匹配空序列并在页面上找不到类时返回空字符串的函数。

let findUrlOrReturnEmptyString (span:seq<HtmlNode>) =
    match span with 
    | Seq.empty -> String.Empty      // <----- This is invalid
    | span -> span
    |> Seq.collect(fun (n:HtmlNode) -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
    |> Seq.last
    |> fun n -> n.AttributeValue("href")

let findMaxPageNumber (page:AnHtmlPage)= 
    page.Html.Descendants()
    |> Seq.filter(fun n -> n.HasClass("paging"))
    |> findUrlOrReturnEmptyStrin

我现在的问题是这Seq.Empty不是文字,不能在模式中使用。大多数具有模式匹配的示例[]在其模式中指定了空列表,所以我想知道:如何使用类似的方法来匹配空序列?

4

4 回答 4

15

ildjarn 在评论中给出的建议是一个很好的建议:如果您觉得 usingmatch会创建更具可读性的代码,那么请创建一个活动模式来检查空序列:

let (|EmptySeq|_|) a = if Seq.isEmpty a then Some () else None

let s0 = Seq.empty<int>

match s0 with
| EmptySeq -> "empty"
| _ -> "not empty"

在 F# 交互中运行它,结果将是"empty".

于 2016-08-12T03:15:23.493 回答
13

您可以使用when警卫来进一步限定案例:

match span with 
| sequence when Seq.isEmpty sequence -> String.Empty
| span -> span
|> Seq.collect (fun (n: HtmlNode) ->
    n.Descendants()
    |> Seq.filter (fun m -> m.HasName("a")))
|> Seq.last
|> fun n -> n.AttributeValue("href")

ildjarn 是正确的,在这种情况下,anif...then...else可能是更易读的替代方案。

于 2016-08-11T22:48:33.537 回答
3

使用保护子句

match myseq with
| s when Seq.isEmpty s -> "empty"
| _ -> "not empty"
于 2019-04-03T16:03:07.220 回答
2

基于@rmunn 的答案,您可以制作更通用的序列相等活动模式。

let (|Seq|_|) test input =
    if Seq.compareWith Operators.compare input test = 0
        then Some ()
        else None

match [] with
| Seq [] -> "empty"
| _ -> "not empty"
于 2016-08-12T07:27:50.160 回答