将字符串 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问题是您的数据集(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 读取数据帧并再次转换为列表而无需字符串