重构 F# 小函数

发布于 2024-11-30 17:50:46 字数 1119 浏览 1 评论 0原文

我创建了以下 F# 函数,它将从网页的 html 内容中获取 url:

let getPicUrl (urlContents : string) =
  let START_TOKEN = "jpg_url="
  let startIndex = urlContents.IndexOf(START_TOKEN)
  let endIndex = urlContents.IndexOf("&amp", startIndex)
  let s = startIndex + START_TOKEN.Length
  let l = endIndex-startIndex-START_TOKEN.Length

  urlContents.Substring(s, l)

最​​后一行 urlContents.Substring(s, l) 实际需要的只是 sl,所以我想知道是否可以将此函数的部分内容重构为一些内部函数,以便我的意图更加清晰。理想情况下,getPicUrl 只会有 2 个 let 指令,sl,所有其他指令都是内部定义这些 let 指令。如果这能以任何方式实现,那就是另一个故事了。

目前我能想到的改进上述代码的唯一明显的方法是切换位置的 endIndex ,这样我们就可以了,

let getPicUrl (urlContents : string) =
  let START_TOKEN = "jpg_url="
  let startIndex = urlContents.IndexOf(START_TOKEN)
  let s = startIndex + START_TOKEN.Length
  let l =
    let endIndex = urlContents.IndexOf("&amp", startIndex)
    endIndex-startIndex-START_TOKEN.Length

  urlContents.Substring(s, l)

但是我一直想知道是否有一种更清晰的方法来组织这个函数的 let 定义。

I've made the following F# function that will get me an url from the html contents of a web page:

let getPicUrl (urlContents : string) =
  let START_TOKEN = "jpg_url="
  let startIndex = urlContents.IndexOf(START_TOKEN)
  let endIndex = urlContents.IndexOf("&", startIndex)
  let s = startIndex + START_TOKEN.Length
  let l = endIndex-startIndex-START_TOKEN.Length

  urlContents.Substring(s, l)

what the last line, urlContents.Substring(s, l), actually needs is only s and l, so I was wondering whether I could refactor parts of this function into some internal functions so I'd let my intentions be clearer. Ideally getPicUrl would only have 2 let instructions, s and l, and all the others would be internal definitions to those let instructions. If this can in any way be achieved or not is another story..

The only obvious way I can think at the moment to improve the above code would be to switch endIndex of place so we'd have

let getPicUrl (urlContents : string) =
  let START_TOKEN = "jpg_url="
  let startIndex = urlContents.IndexOf(START_TOKEN)
  let s = startIndex + START_TOKEN.Length
  let l =
    let endIndex = urlContents.IndexOf("&", startIndex)
    endIndex-startIndex-START_TOKEN.Length

  urlContents.Substring(s, l)

but I keep wondering if there'd be a clearer way of organizing this function's let definitions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-12-07 17:50:46

首先,你的功能有问题。不匹配的字符串会让它变得脾气暴躁。

我喜欢用正则表达式来处理这类事情。使用此活动模式:

open System.Text.RegularExpressions

let (|Regex|_|) pattern input =
  let m = Regex.Match(input, pattern)
  if m.Success then Some(List.tail [for g in m.Groups -> g.Value])
  else None

您可以执行以下操作:

let tryGetPicUrl = function
  | Regex @"jpg_url=([^&]+)&" [url] -> Some url
  | _ -> None

您还可以将原始方法转变为活动模式:

let (|Between|_|) (prefix:string) (suffix:string) (value:string) =
  match value.IndexOf(prefix) with
  | -1 -> None
  | s ->
    let n = s + prefix.Length + 1
    match value.IndexOf(suffix, n) with
    | -1 -> None
    | e -> Some (value.Substring(n, e - n))

并执行以下操作:

let tryGetPicUrl = function
  | Between "jpg_url" "&" url -> Some url
  | _ -> None

Firstly, your function is buggy. A non-matching string will make it grumpy.

I like regexes for this sort of thing. With this active pattern:

open System.Text.RegularExpressions

let (|Regex|_|) pattern input =
  let m = Regex.Match(input, pattern)
  if m.Success then Some(List.tail [for g in m.Groups -> g.Value])
  else None

you can do:

let tryGetPicUrl = function
  | Regex @"jpg_url=([^&]+)&" [url] -> Some url
  | _ -> None

You could also turn your original approach into an active pattern:

let (|Between|_|) (prefix:string) (suffix:string) (value:string) =
  match value.IndexOf(prefix) with
  | -1 -> None
  | s ->
    let n = s + prefix.Length + 1
    match value.IndexOf(suffix, n) with
    | -1 -> None
    | e -> Some (value.Substring(n, e - n))

and do:

let tryGetPicUrl = function
  | Between "jpg_url" "&" url -> Some url
  | _ -> None
笔芯 2024-12-07 17:50:46

你可以这样写:

let getPicUrl (urlContents : string) =
  let s =
    let START_TOKEN = "jpg_url="
    let startIndex = urlContents.IndexOf(START_TOKEN)
    startIndex + START_TOKEN.Length
  let l =
    let endIndex = urlContents.IndexOf("&", s)
    endIndex-s

  urlContents.Substring(s, l)

You can write it this way:

let getPicUrl (urlContents : string) =
  let s =
    let START_TOKEN = "jpg_url="
    let startIndex = urlContents.IndexOf(START_TOKEN)
    startIndex + START_TOKEN.Length
  let l =
    let endIndex = urlContents.IndexOf("&", s)
    endIndex-s

  urlContents.Substring(s, l)
谁与争疯 2024-12-07 17:50:46

另一种选择是使用字符串的 split 方法(我希望字符串不要太长,否则会影响性能)并使用选项类型来指示是否找到 URL。

let getPicUrl (urlContents : string) =
    let splitAndGet n (sep:string) (str:string) = 
        let spl = str.Split([|sep|],StringSplitOptions.None)
        match spl.Length with
        | x when x > n -> Some (spl.[n])
        | _ -> None 
    match urlContents |> splitAndGet 1 "jpg_url=" with
    | Some str -> str |> splitAndGet 0 "&"
    | _ -> None

Another option would be to use split method of string (I hope the string is not too long as that would be a performance hit) and use option type to indicate whether the URL was found or not.

let getPicUrl (urlContents : string) =
    let splitAndGet n (sep:string) (str:string) = 
        let spl = str.Split([|sep|],StringSplitOptions.None)
        match spl.Length with
        | x when x > n -> Some (spl.[n])
        | _ -> None 
    match urlContents |> splitAndGet 1 "jpg_url=" with
    | Some str -> str |> splitAndGet 0 "&"
    | _ -> None
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文