读取文本文件,遍历各行以查找匹配项,然后使用FSharp返回值

时间:2018-11-26 20:06:20

标签: f# f#-fake

我有一个包含以下内容的文本文件,我需要检索分配给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
)

在这一点上,我不知道该如何获取所需的价值。我认为可以使用的选项有:

  • 使用Contains()
  • 正则表达式
  • 记录类型
  • 活动模式

如何获取该值,如果该值不存在则失败?

1 个答案:

答案 0 :(得分:1)

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

我的首选方法是在字符串上使用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)

活动模式技巧很巧妙,但是如果您只需要一个地方,可能会不必要地使代码复杂化。