解析动态列数笨拙的CSV文件会出现错误

时间:2018-08-19 10:27:25

标签: f# f#-data

我是C#开发人员,这是我第一次尝试编写F#。

我正在尝试读取CSV格式的Dashlane导出的数据库。这些文件没有标题,并且每种可能的条目类型都具有动态的列数。以下文件是用于测试软件的虚拟数据的示例。它仅包含password条目,但它们具有5到7列(我将在稍后决定如何处理其他类型的数据) 导出文件的第一行(在这种情况下,但并非总是如此)是用于创建破折号帐户的电子邮件地址,该行使该行仅一列宽。

"accountCreation@email.fr"
"Nom0","siteweb0","Identifiant0","",""
"Nom1","siteweb1","identifiant1","email1@email.email","",""
"Nom2","siteweb2","email2@email.email","",""
"Nom3","siteweb3","Identifiant3","password3",""
"Nom4","siteweb4","Identifiant4","email4@email.email","password4",""
"Nom5","siteweb5","Identifiant5","email5@email.email","SecondIdentifiant5","password5",""
"Nom6","siteweb6","Identifiant6","email6@email.email","SecondIdentifiant6","password6","this is a single-line note"
"Nom7","siteweb7","Identifiant7","email7@email.email","SecondIdentifiant7","password7","this is a 
multi
line note"
"Nom8","siteweb8","Identifiant8","email8@email.email","SecondIdentifiant8","password8","single line note"

我正在尝试将每行的第一列作为开始打印到控制台

let rawCsv = CsvFile.Load("path\to\file.csv", ",", '"', false)       
for row in rawCsv.Rows do
    printfn "value %s" row.[0]

此代码在for行上给了我以下错误

  

无法根据架构解析第2行:预期1列,得到5

我没有给CsvFile提供任何模式,并且在互联网上找不到如何指定模式。

如果我愿意的话,我可以动态删除第一行,但是不会改变任何内容,因为其他行的列数也不同。

有什么方法可以解析F#中的这个笨拙的CSV文件?

注意:对于每一行password,只有最后一行之前的列对我来说很重要(密码列)

2 个答案:

答案 0 :(得分:3)

我认为不像您这样不规则结构的CSV文件是使用CSV Type ProviderCSV Parser处理的不错选择。

与此同时,使用几行自定义逻辑将这个文件解析为您喜欢的文件似乎并不困难。以下代码段:

open System
open System.IO

File.ReadAllLines("Sample.csv") // Get data
|> Array.filter(fun x -> x.StartsWith("\"Nom")) // Only lines starting with "Nom may contain password
|> Array.map (fun x -> x.Split(',') |> Array.map (fun x -> x.[1..(x.Length-2)])) // Split each line into "cells"
|> Array.filter(fun x -> x.[x.Length-2] |> String.IsNullOrEmpty |> not) // Take only those having non-empty cell before the last one
|> Array.map (fun x -> x.[0],x.[x.Length-2]) // show the line key and the password

解析示例文件后产生

>
val it : (string * string) [] =
[|("Nom3", "password3"); ("Nom4", "password4"); ("Nom5", "password5");
("Nom6", "password6"); ("Nom7", "password7"); ("Nom8", "password8")|]
>

这可能是进一步将解析逻辑提高到完美的良好起点。

答案 1 :(得分:2)

我建议将csv文件读取为文本文件。我逐行读取文件并形成一个列表,然后使用CsvFile.Parse解析每一行。但是问题在于,元素是在标头中找到的,而不是在字符串类型为[]选项的行中找到的

*