重构小F#函数

时间:2011-08-20 21:23:51

标签: .net f# refactoring

我已经制作了以下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定义。

3 个答案:

答案 0 :(得分:3)

首先,你的功能是错误的。一个不匹配的字符串会使它变得脾气暴躁。

我喜欢这种类型的正则表达式。有了这种活跃的模式:

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=([^&]+)&amp" [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" "&amp" url -> Some url
  | _ -> None

答案 1 :(得分:2)

你可以这样写:

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("&amp", s)
    endIndex-s

  urlContents.Substring(s, l)

答案 2 :(得分:0)

另一个选择是使用string的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 "&amp"
    | _ -> None