【问题标题】:F# counting chars and hyperlinks in imported URL stringsF# 计算导入的 URL 字符串中的字符和超链接
【发布时间】:2018-12-01 15:45:04
【问题描述】:

我在尝试计算从任何给定网站导入的 url 字符串中 <a ... </a> 超链接/标签的数量时遇到问题。以及计算同一字符串上 char 出现的次数。后者似乎有效,到目前为止我的代码是:

let countChars (url:string) (tag: 'a) =
    let link = fetchUrl (url)
    let rec loop i count =
        if i < link.Length then
            if (link.[i] = tag) then loop (i+1) (count+1)
            else loop (i+1) count
        else count
    loop 0 0

我正在使用以下内容来定义我的 fetchUrl 函数:

let fetchUrl (url:string) : string =
    let req = WebRequest.Create(Uri(url))
    use resp = req.GetResponse()
    use stream = resp.GetResponseStream()
    use reader = new IO.StreamReader(stream)
    in reader.ReadToEnd()

但是我目前被卡住了,因为我无法弄清楚我将如何准确计算导入的 url 字符串上的标签。在我的示例中,我循环遍历 url 字符串,仅计算字符的出现次数,例如“a”,但我似乎无法找到将其应用于我的解决方案的方法,其中作为我实际搜索的子字符串是包含&lt;a ... &lt;/a&gt; 表达式的多个字符的表达式。

我有另一个实现正则表达式的解决方案来尝试处理我正在寻找的标签的实际表达式。这段代码运行了,但是返回值很疯狂:

let countTags (url:string) (tag:string) =
    let link = fetchUrl (url)
    let m = Regex.Match(link,tag)
    let rec loop i count =
        if i < link.Length then
            if m.Success then loop (i+1) (count+1)
            else loop (i+1) count
        else count
    loop 0 0

右图显示了调用此函数得到的结果。

printfn "%A" (countTags "https://forum.astronomisk.dk/" "(?s)<a [^>]*?>(?<text>.*?)</a>") --> result: 75640

printfn "%A" (countTags "https://www.ku.dk/" "(?s)<a [^>]*?>(?<text>.*?)</a>") --> result: 57459

printfn "%A" (countTags "https://www.google.com/" "(?s)<a [^>]*?>(?<text>.*?)</a>") --> result: 47120

结果对应于我对“疯狂”的定义(鉴于本例中的链接为 3 个简单的导入 url 字符串返回大约 47-75k &lt;a href=....&lt;/a&gt; 标签)。使用相同的测试调用导入的 url 字符串上的第一个函数,只寻找 char 'a' 产生大约 2500-3000 的结果,在我看来这是相当合理的,而且似乎工作得很好。

谁能看到我在这里遗漏了什么?我对正则表达式的实现是否不正确,因为它返回了如此高的结果?或者是否有其他方法可以计算任何给定导入的 url 字符串中 &lt;a ... &lt;/a&gt; 标记的数量。我整天都在努力寻找解决方案,但无法通过成功的代码最终关闭项目。

感谢任何帮助修复我剩下的东西!

【问题讨论】:

    标签: url recursion hyperlink f#


    【解决方案1】:

    您的第一个问题是 countTags 似乎在计算您正在查看的文档的长度(如果文档包含锚标记)。

    原因是Regex.Match 搜索匹配的第一次,因此'm.Success' 始终为真。

    你想要的是Regex.Matches。这为您提供了一个 MatchCollection,您可以从中获取“.Count”。

    还可以查看this 以获取匹配锚标记的正则表达式。

    为了澄清,你可以这样做

    let countTags (url:string) (tag:string) =
        let link = fetchUrl url
        let regex = Regex tag
        regex.Matches(link).Count
    

    【讨论】:

    • 嗯,好吧,这很有意义,您将如何实施呢?我看到了使用 Regex.Matches 的想法,但是我需要某种方法在我的计数 if 语句中实现 MatchCollection,让 m = Regex.Mathces(link,tag) let rec loop i count = if i
    • 我还在 F# 中一天天学习,但还是有点新,而且我之前没有使用过 Matches 或 MatchCollection。
    • 嗯好吧,这是有道理的。我确实找到了我正在寻找的答案 :-) 非常感谢您抽出宝贵的时间!
    • 在这种情况下,@KenLar,如果您支持并接受答案作为解决方案,我相信 nilekirk 将不胜感激;)
    • 这很有意义 :) tbh 到目前为止,我只写过几篇文章,所以我并没有真正意识到用这种方法来结束我的问题。但当然,这很有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2016-06-07
    • 1970-01-01
    • 2019-09-14
    • 2023-04-06
    • 2017-03-16
    相关资源
    最近更新 更多