将字符串 csv 转换为对象列表

Posted

技术标签:

【中文标题】将字符串 csv 转换为对象列表【英文标题】:convert string csv to List of objects 【发布时间】:2016-06-24 09:05:36 【问题描述】:

我有以下刺痛

const string csv = "Foo1,Foo2,Foo3,Foo4,Foo5,Foo6,Ping Pong\n" +
                   "2016-02-29,1437.530029,1445.839966,1433.77002,1436.930054,34016300,1436.930054\n" +
                   "2016-02-25,1431.439941,1431.439941,1421.280029,1426.97998,78076500,1426.97998\n" +
                   "2016-02-24,1430.459961,1432.430054,1417.449951,1419.790039,29049900,1419.790039\n";

如何将其转换为 List<Model> 在哪里

public class Model

    public string Foo1  get; set; 
    public string Foo2  get; set; 
    public string Foo3  get; set; 
    public string Foo4  get; set; 
    public string Foo5  get; set; 
    public string Foo6  get; set; 
    public string Ping_Pong  get; set; 

注意我的原始 csv 中的 Ping Pong 标头

我尝试使用CsvHelper,但没有成功,因为它采用的是流而不是字符串,我尝试转换解析失败

EDIT 是否使用CsvHelper对我来说无所谓,最后我想将csv转换为List<Model>

我该怎么做?

【问题讨论】:

为什么不在这里实现自定义解析逻辑? 或者你可以很容易地将字符串转换为流: var ms = new MemoryStream(new UTF8Encoding.GetBytes(csv)); 有一些方法可以将string 转换为Stream ***.com/questions/1879395/… 我建议你不要放弃 csvhelper——我已经取得了很大的成功。它可以使用 TextReader,您可以使用 StringReader 向阅读器显示您的字符串: var myReader = new StringReader(thecsvString): 【参考方案1】:

您可以使用csv 变量创建StringReader

var textReader = new StringReader(csv);

var csvr = new CsvReader(textReader);
var records = csvr.GetRecords<Model>();

如果你想要自己的解析器:

var lines = csv.Split(new char[] '\n', StringSplitOptions.RemoveEmptyEntries).Skip(1);
List<Model> models = new List<Model>();

foreach (var item in lines)

    var values = item.Split(',');
    var model = new Model
    
        Foo1 = values[0],
        Foo2 = values[1],
        Foo3 = values[2],
        Foo4 = values[3],
        Foo5 = values[4],
        Foo6 = values[5],
        Ping_Pong = values[6],
    ;

    models.Add(model);

编辑:

要使用CsvHelper 解决标头问题,您需要创建一个映射配置类,指定标头和属性之间的映射:

public class ModelMap : CsvClassMap<Model>

    public ModelMap()
    
        Map(m => m.Foo1);
        Map(m => m.Foo2);
        Map(m => m.Foo3);
        Map(m => m.Foo4);
        Map(m => m.Foo5);
        Map(m => m.Foo6);
        Map(m => m.Ping_Pong).Name("Ping Pong");
    

这样使用:

var textReader = new StringReader(csv);

var csvr = new CsvReader(textReader);
csvr.Configuration.RegisterClassMap<ModelMap>();

var records = csvr.GetRecords<Model>();

【讨论】:

这很好用,我的问题是如何将标题分配给模型类中的正确属性?我更喜欢而不是阅读 [x] 地方 您可以使用 Split(params char[] separators) 重载来执行 csv.Split('\n'),因为您实际上并不需要删除 OP 示例的空条目。 @juharr:是我的第一次尝试,但csv 最后有一个\n。 params 重载最后返回一个空行。 在测试你的第二个答案时不知何故对我不起作用。 var 记录 = csvr.GetRecords();给我空 @user829174: StockModel 和 Model 一样吗?如果没有注意,您需要创建从 CsvClassMap 继承的地图【参考方案2】:

问题是您的数据集(csv 字符串)缺少一列(您指定 7 列,但 csv 中缺少 Ping Pong 列)。默认行为是抛出,但您可以设置一个配置选项来忽略丢失的列:

这是工作代码:

var config = new CsvConfiguration();
// setting this will cause the missing Ping Pong field to be ignored
config.WillThrowOnMissingField = false;

// we wrap your string in a StringReader to make it accessible to CsvReader
var reader = new CsvReader(new StringReader(csv), config);
var records = reader.GetRecords<Model>().ToList();
records.Dump();

【讨论】:

我确实有“乒乓球”数据,我在我的问题中加倍检查。我在标题中有 7 个值(乒乓球之间有空格)和数据中有 7 个值 @user829174 你说得对,我记错了。我将您的标题从“Ping Pong”重命名为“Ping_Pong”,因此它与您的模型匹配,现在所有 7 列都解析【参考方案3】:

要完全按照你的要求做,你可以使用这个:

var modelStrings = csv.Split('\n').Skip(1);
var models = new List<Model>();
foreach(string s in modelStrings)

    var props = s.Split(',');
    models.Add(new Model(props[0],props[1],props[2],props[3],props[4],props[5],props[6]));


但请注意:这可能很慢,您可能需要添加更广泛的逻辑来实例化新模型,以解决 csv 格式可能发生的变化。

编辑:

为了澄清这是做什么的,它首先通过跳过第一行的新行来拆分 csv 字符串。然后它使用该列表中的每个字符串并用逗号分隔它们以获取值列表(模型属性)以实例化 Model 类

【讨论】:

不确定它会起作用,什么是'foreach(模型中的字符串s)'? 哎呀我改了一个变量名,让我编辑我的答案 您的第一次拆分也将在“Ping Pong”中的空间上拆分。 我喜欢使用像 csvreader 这样的库而不是手动解析的一个原因是阅读器将处理 Excel 的 csv 格式的数据。这对于 OP 的使用可能或可能无关紧要,但这里有一个例子:如果数据值之一是逗号(所以你想要那个逗号,它不是分隔符),Excel 会将该值放在引号中,你会忽略引号内的任何逗号。 CsvHelper 内置了所有解析逻辑。只是需要知道一些东西——对于 OP 的需要来说可能是多余的,但可能不是。 @juharr 啊,好吧,我相信我误解了关于拆分文档的信息,我更新了它,所以它应该不再是问题了

以上是关于将字符串 csv 转换为对象列表的主要内容,如果未能解决你的问题,请参考以下文章

将列表写入 pandas 数据帧到 csv,从 csv 读取数据帧并再次转换为列表而无需字符串

如何将 csv 字符串转换为 pandas 中的列表?

如何将 csv 字符串转换为 pandas 中的列表?

如何将 csv 文件转换为可作为文本读取的列表列表? Python

pandas - 将字符串转换为字符串列表[重复]

如何将对象列表转换为 csv?