【问题标题】:Reading "Awkward" CSV Files with FSharp CsvParser使用 FSharp CsvParser 读取“尴尬”的 CSV 文件
【发布时间】:2017-12-08 06:43:52
【问题描述】:

我有一个大文件(200K - 300K 行文本)。 它几乎是一个 CSV 文件,但并不完全是一个 CSV 文件。

  1. 列标题在第二行,有一行虚拟文本
    在此之前。

  2. 实际数据行中散布着一些行。他们有 逗号,但大多数列都是空白的。它们与我无关。

我需要有效地读取这个文件,并解析实际上是 有效,作为 CSV 数据。

我的第一个想法是编写一个干净的程序,去掉第一行和空白行,只留下我想要的标题和细节 在 CsvParser 可以读取的 CSV 文件中。

这很简单,只需从 StreamReader 中读取行,我可以通过将其视为字符串来保留或忽略每一行。

现在虽然我有一个新问题。

有效数据中有一个列,我可以使用它来忽略更多行。

如果我使用 CsvParser 读取 Cleaned 文件,则很容易按该列进行过滤。

但是,我真的不想浪费将不需要的行写入 Clean 文件。

我希望能够在清理文件时检查该列。但是,那时我正在使用代表整行的字符串。想要找到具体的专栏并不容易。

我不能在 ',' 上拆分,其他列的文本中可能有逗号。 我最终要编写 Csv Parsing Logic,我最初使用的是 CsvParser。

理想情况下,我想读取现有文件,清除我可以基于字符串的行,然后使用 CsvParser 以某种方式解析生成的 seq。

我看到 CsvFile 可以从 Streams 和 Readers 加载,但我不确定这有多大帮助。

有什么建议还是我问的太多了?我应该只处理加载清理文件时的额外过滤吗?

【问题讨论】:

  • 仅供参考,在没有任何更好的想法的情况下,我最初写的是一个临时文件,其中删除了格式错误的行。然后使用 CsvParser 过滤其他行并写入实际的 Clean File。
  • 如果您向我们展示文件的外观,我们会更容易提供帮助。不是全部 200k 行,但足以抓住问题的本质。从描述来看,我认为不到 10 行就可以实现。
  • 最好能看到一个样本,即使有一个要点的链接。我认为您使用 tmp 文件的初始解决方案是有意义的。您可以探索的另外两种方法是指定 csv 文件的架构并使用忽略错误选项;或使用其他 .net csv 解析器,例如 FileHelpers。

标签: f# f#-data


【解决方案1】:

直接使用CsvFile类可以避免大部分解析工作。

F# Data documentation 有一些扩展示例,详细说明了如何执行此操作。

在文件开头跳过行由skipRows 参数处理。传递ignoreErrors 参数也会忽略解析失败的行。

open FSharp.Data
let csv = CsvFile.Load(file, skipRows=1, ignoreErrors=true)
for row in csv.Rows do
    printfn "%s" row.GetColumn "Name"

如果您必须对行进行更复杂的过滤,一种不需要临时文件的简单方法是过滤File.ReadLines 的结果并将其传递给CsvFile.Parse

下面的示例跳过了六行前奏,逐行读取直到遇到空行,使用CsvFile 解析数据,最后将结果行过滤到感兴趣的行。

let tableA =
    File.ReadLines(file)
    |> Seq.skip(6) 
    |> Seq.takeWhile(fun l -> String.length l > 0) 
    |> String.concat "\n"

let csv = CsvFile.Parse(tableA)
for row in csv.Rows.Filter(fun row -> row?Close.AsFloat() > row?Open.AsFloat()) do
    printfn "%s" row.GetColumn "Name"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    相关资源
    最近更新 更多