F# 分析具有动态列数的CSV文件时出错

F# 分析具有动态列数的CSV文件时出错,f#,f#-data,F#,F# Data,我是一名C开发人员,这是我第一次尝试编写F 我正在尝试读取CSV格式的Dashlane导出数据库。对于每种可能的条目类型,这些文件没有标题和动态列数。下面的文件是我用来测试软件的虚拟数据示例。它只包含密码条目,但它们有5到7列,我稍后将决定如何处理其他类型的数据 在本例中,导出文件的第一行(但不总是)是用于创建dashlane帐户的电子邮件地址,这使得此行仅为一列宽 "accountCreation@email.fr" "Nom0","siteweb0","Identifiant0","",""

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

我正在尝试读取CSV格式的Dashlane导出数据库。对于每种可能的条目类型,这些文件没有标题和动态列数。下面的文件是我用来测试软件的虚拟数据示例。它只包含密码条目,但它们有5到7列,我稍后将决定如何处理其他类型的数据 在本例中,导出文件的第一行(但不总是)是用于创建dashlane帐户的电子邮件地址,这使得此行仅为一列宽

"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任何模式,在internet上也找不到如何指定模式

如果我愿意,我可以动态删除第一行,但它不会改变任何东西,因为其他行也有不同的列计数

有没有办法用F解析这个awakward CSV文件


注意:对于每个密码行,只有最后一行之前的一列对我很重要密码列

我不认为像您这样结构不规则的CSV文件适合使用或进行处理

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

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")|]
>

这可能是进一步完善解析逻辑的一个很好的起点。

我不认为像您这样结构不规则的CSV文件适合使用或进行处理

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

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")|]
>

这可能是进一步完善解析逻辑的良好起点。

我建议将csv文件作为文本文件阅读。我逐行读取文件并形成一个列表,然后用CsvFile.parse解析每一行。但问题是,这些元素是在标题中找到的,而不是在string[]option类型的行中找到的

 open  FSharp.Data
 open System.IO

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

 [<EntryPoint>]
 let main argv = 
     let lines = readLines "c:\path_to_file\example.csv"
     let rows = List.map (fun str -> CsvFile.Parse(str)) (Seq.toList lines)
     for row in List.toArray(rows) do
         printfn "New Line"
         if row.Headers.IsSome then 
             for r in row.Headers.Value do
                 printfn "value %s" (r)
     printfn "%A" argv
     0 // return an integer exit code

我建议将csv文件作为文本文件读取。我逐行读取文件并形成一个列表,然后用CsvFile.parse解析每一行。但问题是,这些元素是在标题中找到的,而不是在string[]option类型的行中找到的

 open  FSharp.Data
 open System.IO

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

 [<EntryPoint>]
 let main argv = 
     let lines = readLines "c:\path_to_file\example.csv"
     let rows = List.map (fun str -> CsvFile.Parse(str)) (Seq.toList lines)
     for row in List.toArray(rows) do
         printfn "New Line"
         if row.Headers.IsSome then 
             for r in row.Headers.Value do
                 printfn "value %s" (r)
     printfn "%A" argv
     0 // return an integer exit code

我的CSV文件中没有标题。这个代码还能用吗?我不明白row.Headers在没有值的情况下怎么会有值…而且,我最终用C重新编写了程序,通过逐字符读取来解析文件。。。但我仍然被F解决方案所困扰。我的CSV文件中没有标题。这个代码还能用吗?我不明白row.Headers在没有值的情况下怎么会有值…而且,我最终用C重新编写了程序,通过逐字符读取来解析文件。。。但我仍然对F解决方案感兴趣。我同意可能需要实践逻辑,这就是为什么我实际上用C编写了这个库,我比F更容易编写。我将尝试使用您的代码用F重新编写我的库。我将看看如何修改它,以便它接受任何数据集。名称字段不一定包含名称字符串:-谢谢!我同意可能需要使用逻辑,这就是为什么我实际上用C编写了这个库,我比F更容易编写。我将尝试使用您的代码用F重新编写我的库。我将看看如何修改它,以便它接受任何数据集。名称字段不必包含名称字符串:-谢谢!