读取文本文件,遍历行以找到匹配项,并使用 FSharp return 值

Reading text file, iterating over lines to find a match, and return the value with FSharp

我有一个包含以下内容的文本文件,我需要检索分配给 taskId 的值,在本例中为 AWc34YBAp0N7ZCmVka2u.

projectKey=ProjectName
serverUrl=http://localhost:9090
serverVersion=10.5.32.3
strong text**interfaceUrl=http://localhost:9090/interface?id=ProjectName
taskId=AWc34YBAp0N7ZCmVka2u
taskUrl=http://localhost:9090/api/ce/task?id=AWc34YBAp0N7ZCmVka2u

我有两种不同的方式来读取我写的文件。

let readLines (filePath:string) = seq {
 use sr = new StreamReader (filePath)
 while not sr.EndOfStream do
     yield sr.ReadLine ()
}

readLines (FindFile currentDirectory "../**/sample.txt")
|> Seq.iter (fun line -> 
   printfn "%s" line
)

let readLines (filePath:string) = 
  (File.ReadAllLines filePath)

readLines (FindFile currentDirectory "../**/sample.txt")
|> Seq.iter (fun line -> 
   printfn "%s" line
)

在这一点上,我不知道如何获得我需要的价值。我认为 table 上的选项是:

如果这个值不存在,我如何返回并失败?

我认为所有选项都是合理的 - 这取决于文件的实际复杂程度。如果没有转义,那么您可能只需要在行中查找 = 并使用它将行拆分为键值对。如果语法更复杂,这可能并不总是有效。

我的首选方法是在字符串上使用 Split - 然后您可以 filter 使用所需的键查找值, map 获取值并使用 Seq.head获取值:

["foo=bar"]
|> Seq.map (fun line -> line.Split('='))
|> Seq.filter (fun kvp -> kvp.[0] = "foo")
|> Seq.map (fun kvp -> kvp.[1])
|> Seq.head

使用活动模式,您可以定义一个模式,该模式接受一个字符串并使用 = 将其拆分为一个列表:

let (|Split|) (s:string) = s.Split('=') |> List.ofSeq

然后,您可以使用 Seq.pick 和模式匹配来获取值,该模式匹配查找 = 之前的子字符串为例如的字符串。 foo:

["foo=bar"] |> Seq.pick (function
  | Split ["foo"; value] -> Some value
  | _ -> None)

活动模式技巧非常简洁,但如果您只在一个地方需要它,它可能会使代码不必要地复杂化。